【问题标题】:Eclipse CDT syntax error for macro using _Generic keyword使用 _Generic 关键字的宏的 Eclipse CDT 语法错误
【发布时间】:2017-08-26 23:26:52
【问题描述】:

我正在使用内置 CDT 9.3.0 的 Oxygen。

当我使用我定义的使用 _Generic 的宏时,所有这些宏使用都带有“语法错误”下划线,但项目编译良好(设置为使用我的 makefile)。

在阅读了similar 这样的问题后,并且由于 Eclipse 的代码分析可能不支持 _Generic 从 C11 开始,我尝试为我的宏定义定义一个符号为空,但它不起作用。 (在项目设置中,C/C++ General->Paths and Symbols->Symbols Tab,GNU C,添加了不带值的符号 CONVERT(...) 并添加了符号 CONVERT(X),以及不带值的 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");

【问题讨论】:

  • _Generic 来自 C11 标准。据我所知,Eclipse 的“智能感知”还不支持它。

标签: c eclipse-cdt


【解决方案1】:

正如@ErikW 所指出的,_Generic 是 Eclipse CDT 的解析器尚不支持的 C11 功能。 This bug 跟踪添加对它的支持。

(顺便说一下,contributions 对 Eclipse CDT 的 C11 支持非常欢迎!)


可以使用宏来解决这个问题。

尝试在“路径和符号”中定义另一个版本的CONVERT(...) 宏的问题在于,在那里定义的宏被视为您将它们写在文件的最顶部。实际代码中的后续重新定义会覆盖“路径和符号”中的定义。

我可以想到两种方法来解决这个问题:


方法 1

CDT 定义了一个特殊的宏 __CDT_PARSER__,它在解析代码时评估为 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(...) 的空扩展。我们想要一个将解析为变量初始化器的扩展。 0 将起作用:

#ifdef __CDT_PARSER__
    #define CONVERT(...) 0
#else
    ...
#endif

方法 2

我们可以将_Generic(...) 本身定义为CDT 的宏,而不是定义不同版本的CONVERT(...)

这一次,我们可以在“路径和符号”中进行,因为代码中没有重新定义 _Generic(...) 会搞砸。

所以让我们在“路径和符号”中定义一个符号,名称为_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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    相关资源
    最近更新 更多