如何让Doxygen正确识别用作泛型的C宏(如OPTIONAL)?
问题场景
我用C语言的宏模拟泛型特性,实现了类似可选值的结构:
#define OPTIONAL( T ) struct{ bool present; T data; } OPTIONAL( size_t ) Example1( size_t x ) { return x ? { true, x - 1 } : { false, 0 }; }
但在typedef场景下用Doxygen文档化时出现错误识别:
/** @brief example */ typedef OPTIONAL( size_t ) optional_size_t;
Doxygen抛出警告:warning: return type of member OPTIONAL is not documented,它错误地将这段代码识别为名为OPTIONAL的函数定义,完全忽略了真正的typedef目标optional_size_t。
需求
- 不启用
MACRO_EXPANSION配置(宏展开后的类型结构杂乱,宏本身的语义文档更清晰) - 希望Doxygen将
OPTIONAL( size_t )视为类似std::optional<std::size_t>的结构,生成指向OPTIONAL宏和size_t类型的链接
使用Doxygen版本1.9.5,相关配置项:
OPTIMIZE_OUTPUT_FOR_C = YES QUIET = YES WARN_NO_PARAMDOC = YES RECURSIVE = YES
解决方案
方案1:显式使用@typedef命令
在注释中用@typedef明确告知Doxygen当前是typedef声明,同时给OPTIONAL宏补充文档,让Doxygen正确关联类型与宏:
/** @brief 生成可选值结构的泛型宏 * @param *T* 可选值存储的底层数据类型 */ #define OPTIONAL( T ) struct{ bool present; T data; } /** @brief 基于size_t的可选值类型 * @typedef optional_size_t * @details 由OPTIONAL(size_t)宏生成的结构类型 */ typedef OPTIONAL( size_t ) optional_size_t;
这样Doxygen会正确识别optional_size_t为typedef类型,同时保留OPTIONAL宏的文档链接,自动生成到size_t的类型链接。
方案2:用@hideinitializer避免宏误判
给OPTIONAL宏添加@hideinitializer标签,阻止Doxygen将宏的参数解析为函数参数,同时用@name对相关类型进行分组:
/** @brief 生成可选值结构的泛型宏 * @param *T* 可选值存储的底层数据类型 * @hideinitializer */ #define OPTIONAL( T ) struct{ bool present; T data; } /** @name 具体可选值类型 * @{ */ /** @brief 基于size_t的可选值类型 */ typedef OPTIONAL( size_t ) optional_size_t; /** @} */
@hideinitializer会让Doxygen将OPTIONAL(T)视为类型构造器而非函数,既保留宏的语义文档,又能正确识别typedef。
方案3:配置宏别名模拟模板结构
在Doxygen配置文件中添加MACRO_ALIASES,将OPTIONAL(T)映射为Doxygen可识别的模板风格结构:
MACRO_ALIASES += "OPTIONAL(T)=@ref OPTIONAL_template<T>"
然后给OPTIONAL宏添加模板风格的文档注释:
/** @brief 模拟模板特性的可选值宏 * @tparam *T* 可选值存储的底层数据类型 * @name OPTIONAL_template */ #define OPTIONAL( T ) struct{ bool present; T data; }
这种方式能让Doxygen将OPTIONAL(size_t)识别为带参数的模板类型,生成类似C++std::optional的文档结构,同时生成到OPTIONAL宏和size_t的链接。
内容的提问来源于stack exchange,提问作者Sam Coutteau

