【问题标题】:_Generic() macro not expanding_Generic() 宏未扩展
【发布时间】:2016-03-17 02:10:55
【问题描述】:

所以我正在尝试实现一个“通用打印宏”:

#include <stdio.h>
#include <float.h>

#define CHECK(x) printf(#x " =" \
        _Generic((x), float: double: "%f",\
                  int: "%d",\
                  default: "Cannot print this with CHECK(x)")\
        , x)

int main(void){
    CHECK(FLT_RADIX);
    return 0;
}

这给了我错误:

main.c:11:2: error: expected ')'
        CHECK(FLT_RADIX);
        ^
main.c:5:3: note: expanded from macro 'CHECK'
                _Generic((x), float: double: "%f",\
                ^
main.c:11:2: note: to match this '('
main.c:4:24: note: expanded from macro 'CHECK'
#define CHECK(x) printf(#x " =" \
                       ^
1 error generated.

运行clang main.c -E后,输出为:

int main(void){
 printf("FLT_RADIX" " =" _Generic((2), float: double: "%f", int: "%d", default: "Cannot print this with CHECK(x)") , 2);
 return 0;
}

那么如何让_Generic()在翻译过程中展开呢?

顺便说一句:我不匹配哪个)

【问题讨论】:

  • 我认为您不能像这样将 float:double: 术语组合在一起 - 这是错误消息的来源。也许你应该在default: 子句中使用静态断言,这样如果代码不起作用,代码就不会编译。
  • 另一种可能的解决方案是#define CHECK(X) (printf("%s", #x " ="), printf(_Generic(.......(保持原样,修复下面 Jonathan Leffler 指出的问题)
  • @JonathanLeffler:实际上有两个错误。你提到的那个会在正文后面出现(见错误标记)。
  • 几个很好的例子(太长了,不能在这里发布)可以在:http://www.robertgamble.net/2012/01/c11-generic-selections.html
  • "我正在尝试实现一个"通用打印宏":" --> 这可能会有所帮助 Formatted print without the need to specify type matching specifiers using _Generic

标签: c clang c-preprocessor


【解决方案1】:

_Generic 不是宏,而是primary expression(另见 6.5.1.1)。因此,它在比字符串连接(阶段 6)更晚的翻译阶段(7)进行评估。请参阅标准5.1.1.2。简而言之:当编译器连接字符串时,_Generic 尚未被评估。

您必须将转换后的值作为字符串参数传递给printf 或调用单独的printf,并使用格式字符串作为值。使宏保持较小的一种方法是使用辅助函数,您传递类型代码加上union 中的实际值。然后该函数将使用switch 进行转换和打印。或者您为每种类型使用不同的功能。当然有多种选择。

好的,这是一个(不一定是最好的)方法:

#define CHECK(x) _Generic((x), double: print_as_double(#x, x), \
                  float: print_as_double(#x, x),
                  int: print_as_int(#x, x), \
                  default: printf("Cannot print this with CHECK(x)") )

void print_as_float(const char *name, double value)
{
    printf("%s = %lf", value);
}

...

请注意,您不能在 generic-association 中组合不同的类型名称,这就是我必须拆分 floatdouble 条目的原因。

旁注:名称CHECK 具有误导性,因为函数在运行时并没有真正检查某些内容。一个更好的名字将是例如“PRINT_VALUE”。

【讨论】:

  • 你的意思是像printf("%s", "%d", 42);这样的东西吗?这行不通
  • @sunqingyao:printf 无法做到这一点。您不能嵌套格式字符串。但是你可以写一个小的meta-printf
  • @sunqingyao 不是,他的意思是printf("%d", 42);
猜你喜欢
  • 2016-02-27
  • 1970-01-01
  • 2016-07-28
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多