使用 _Generic 关键字的宏的 Eclipse CDT 语法错误
Eclipse CDT syntax error for macro using _Generic keyword
我正在使用内置 CDT 9.3.0 的 Oxygen。
当我使用我定义的使用 _Generic 的宏时,所有这些宏的使用都带有 "syntax error" 下划线,但项目编译正常(设置为使用我的 makefile)。
在阅读了一个 similar so 问题后,由于 _Generic 从 C11 开始可能不受 eclipse 代码分析的支持,我尝试为我的宏定义定义一个符号为空,但它没有用。 (在项目设置中,C/C++ General->Paths and Symbols->Symbols Tab, GNU C, added symbol CONVERT(...) without a value and added a symbol CONVERT(X), and CONVERT()和 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 指出的那样,_Generic
是 Eclipse CDT 的解析器尚不支持的 C11 功能。 This bug tracks 添加了对它的支持。
(顺便说一句,非常欢迎contributions对Eclipse CDT的C11支持!)
可以使用宏解决此问题。
尝试在 "Paths and Symbols" 中定义另一个版本的 CONVERT(...)
宏的问题在于,在那里定义的宏被视为您将它们写在文件的最顶部。实际代码中的后续重新定义会覆盖 "Paths and Symbols".
中的定义
我可以想到两种方法来解决这个问题:
方法一
CDT 定义了一个特殊的宏 __CDT_PARSER__
,它在解析代码时计算结果为真,但在实际编译代码时计算结果为假。
您可以利用它为 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(...)
的空扩展。我们想要一个将解析为变量初始值设定项的扩展。 0
有效:
#ifdef __CDT_PARSER__
#define CONVERT(...) 0
#else
...
#endif
方法二
我们可以将 _Generic(...)
本身定义为用于 CDT 目的的宏,而不是定义 CONVERT(...)
的不同版本。
这一次,我们可以在"Paths and Symbols"中进行,因为代码中没有重新定义_Generic(...)
会搞砸
所以让我们在"Paths and Symbols"中定义一个符号,名称为_Generic(...)
,值为空。
现在,这一行:
void* test = CONVERT("testme", 42);
将扩展为:
void* test = _Generic((FIRST("testme", 42)), \
char* : toText, \
int : toInt, \
) ("testme", 42)
这将依次扩展为:
void* test = ("testme", 42);
它解析(("testme", 42)
解析为带括号的逗号表达式,因此是一个有效的初始值设定项)。
这种方法的优点是您不需要修改实际代码,并且它处理 _Generic
宏的所有使用,而不仅仅是 CONVERT
中的那个。
另一方面,对于 _Generic
宏的某些其他用途,此特定扩展可能无法解析。如果是这种情况,您可能会想出一个不同的扩展来解析所有用途,否则您可以使用方法 1。
我正在使用内置 CDT 9.3.0 的 Oxygen。
当我使用我定义的使用 _Generic 的宏时,所有这些宏的使用都带有 "syntax error" 下划线,但项目编译正常(设置为使用我的 makefile)。
在阅读了一个 similar so 问题后,由于 _Generic 从 C11 开始可能不受 eclipse 代码分析的支持,我尝试为我的宏定义定义一个符号为空,但它没有用。 (在项目设置中,C/C++ General->Paths and Symbols->Symbols Tab, GNU C, added symbol CONVERT(...) without a value and added a symbol CONVERT(X), and CONVERT()和 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 指出的那样,_Generic
是 Eclipse CDT 的解析器尚不支持的 C11 功能。 This bug tracks 添加了对它的支持。
(顺便说一句,非常欢迎contributions对Eclipse CDT的C11支持!)
可以使用宏解决此问题。
尝试在 "Paths and Symbols" 中定义另一个版本的 CONVERT(...)
宏的问题在于,在那里定义的宏被视为您将它们写在文件的最顶部。实际代码中的后续重新定义会覆盖 "Paths and Symbols".
我可以想到两种方法来解决这个问题:
方法一
CDT 定义了一个特殊的宏 __CDT_PARSER__
,它在解析代码时计算结果为真,但在实际编译代码时计算结果为假。
您可以利用它为 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(...)
的空扩展。我们想要一个将解析为变量初始值设定项的扩展。 0
有效:
#ifdef __CDT_PARSER__
#define CONVERT(...) 0
#else
...
#endif
方法二
我们可以将 _Generic(...)
本身定义为用于 CDT 目的的宏,而不是定义 CONVERT(...)
的不同版本。
这一次,我们可以在"Paths and Symbols"中进行,因为代码中没有重新定义_Generic(...)
会搞砸
所以让我们在"Paths and Symbols"中定义一个符号,名称为_Generic(...)
,值为空。
现在,这一行:
void* test = CONVERT("testme", 42);
将扩展为:
void* test = _Generic((FIRST("testme", 42)), \
char* : toText, \
int : toInt, \
) ("testme", 42)
这将依次扩展为:
void* test = ("testme", 42);
它解析(("testme", 42)
解析为带括号的逗号表达式,因此是一个有效的初始值设定项)。
这种方法的优点是您不需要修改实际代码,并且它处理 _Generic
宏的所有使用,而不仅仅是 CONVERT
中的那个。
另一方面,对于 _Generic
宏的某些其他用途,此特定扩展可能无法解析。如果是这种情况,您可能会想出一个不同的扩展来解析所有用途,否则您可以使用方法 1。