_Generic() 宏不扩展

_Generic() macro not expanding

所以我正在尝试实现 "generic printing macro":

#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()在翻译的时候展开呢?

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

_Generic不是宏,而是primary expression (see also 6.5.1.1). As such it is evaluated at a later translation phase (7) than string concatenation (phase 6). See the standard, 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);
}

...

请注意,您不能在 通用关联 中组合不同的类型名称,这就是为什么我必须拆分 floatdouble 条目的原因。

旁注:名称 CHECK 具有误导性,因为这些函数并不真正在 运行 时检查某些内容。更好的名字是例如"PRINT_VALUE".