_Generic()宏没有扩展

时间:2016-03-17 02:10:55

标签: c clang c-preprocessor

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

#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()

BTW:哪个)我不匹配?

1 个答案:

答案 0 :(得分:8)

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

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

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

#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);
}

...

请注意,您无法在泛型关联中组合不同的类型名称,这就是我必须拆分floatdouble条目的原因。

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