使用_Generic关键字的宏的Eclipse CDT语法错误
我使用的是内置CDT9.3.0的氧气 当我使用我定义的使用_Generic的宏时,所有这些宏的使用都带有“syntax error”的下划线,但是项目编译很好(设置为使用我的makefile) 在阅读了一个so问题之后,由于eclipse的代码分析可能不支持从C11开始的泛型,我尝试将宏定义的符号定义为空,但没有成功。(在项目设置中,C/C++常规->路径和符号->符号选项卡,GNU C,添加了不带值的符号转换(…),并添加了符号转换(X),以及CONVERT()和不带值的转换) 例如,我的宏是:使用_Generic关键字的宏的Eclipse CDT语法错误,c,eclipse-cdt,C,Eclipse Cdt,我使用的是内置CDT9.3.0的氧气 当我使用我定义的使用_Generic的宏时,所有这些宏的使用都带有“syntax error”的下划线,但是项目编译很好(设置为使用我的makefile) 在阅读了一个so问题之后,由于eclipse的代码分析可能不支持从C11开始的泛型,我尝试将宏定义的符号定义为空,但没有成功。(在项目设置中,C/C++常规->路径和符号->符号选项卡,GNU C,添加了不带值的符号转换(…),并添加了符号转换(X),以及CONVERT()和不带值的转换) 例如,我的宏是
#define FIRST_(_1, ...) _1
#define FIRST(...) FIRST_(__VA_ARGS__, _1, _2, _3)
#define CONVERT(...) \
_Generic((FIRST(__VA_ARGS__)), \
char* : toText, \
int : toInt, \
) (__VA_ARGS__)
和使用点,这会导致语法错误:
void* test = CONVERT("testme");
正如@ErikW指出的,
\u Generic
是一个C11特性,Eclipse CDT的解析器还不支持它。跟踪添加对它的支持
(顺便说一句,非常欢迎使用Eclipse CDT的C11支持!)
可以使用宏来解决这个问题 试图在“路径和符号”中定义另一个版本的
CONVERT(…)
宏的问题在于,此处定义的宏被视为是在文件的最顶端编写的。实际代码中的后续重新定义将覆盖“路径和符号”中的定义
我可以想出两种方法来实现这一点:
方法1 CDT定义了一个特殊的宏
\uuu CDT\u PARSER\uuu
,它在解析代码时计算为true,但在实际编译代码时计算为false
您可以利用此功能为CDT定义不同版本的CONVERT(…)
:
#ifdef __CDT_PARSER__
#define CONVERT(...)
#else
#define CONVERT(...) \
_Generic((FIRST(__VA_ARGS__)), \
char* : toText, \
int : toInt, \
) (__VA_ARGS__)
#endif
这几乎有效,但不完全有效。我们仍然会遇到语法错误,因为这一行:
void* test = CONVERT("testme", 42);
void* test = CONVERT("testme", 42);
现在将扩展到:
void* test = ;
void* test = _Generic((FIRST("testme", 42)), \
char* : toText, \
int : toInt, \
) ("testme", 42)
void* test = ("testme", 42);
正如您所看到的,我们实际上不希望CONVERT(…)
的扩展为空。我们需要一个将解析为变量初始值设定项的扩展<代码>0将起作用:
#ifdef __CDT_PARSER__
#define CONVERT(...) 0
#else
...
#endif
方法2 我们可以将
\u Generic(…)
本身定义为用于CDT的宏,而不是定义不同版本的CONVERT(…)
这一次,我们可以在“路径和符号”中这样做,因为在代码中没有对\u Generic(…)
的重新定义会把它搞砸
因此,让我们在“路径和符号”中定义一个符号,名称为\u Generic(…)
,值为空
现在,这一行:
void* test = CONVERT("testme", 42);
void* test = CONVERT("testme", 42);
将扩展到:
void* test = ;
void* test = _Generic((FIRST("testme", 42)), \
char* : toText, \
int : toInt, \
) ("testme", 42)
void* test = ("testme", 42);
这将反过来扩展到:
void* test = ;
void* test = _Generic((FIRST("testme", 42)), \
char* : toText, \
int : toInt, \
) ("testme", 42)
void* test = ("testme", 42);
解析((“testme”,42)
解析为带括号的逗号表达式,因此是有效的初始值设定项)
这种方法的优点是,您不需要修改实际代码,而且它可以处理\u Generic
宏的所有用法,而不仅仅是CONVERT
中的用法
另一方面,对于
\u Generic
宏的某些其他用途,此特定扩展可能无法解析。如果是这样的话,您可能会想出一个不同的扩展来解析所有用途,或者您可以使用方法1。\u Generic
来自C11标准。据我所知,Eclipse的“智能感知”还不支持它。