[英]gcc -E does not expand C11 _Generic expressions
In a C11 library project I have a couple of macro functions that are exposed under a shared macro name using generics, like this: 在C11库项目中,我有一些使用泛型在共享宏名称下公开的宏函数,如下所示:
#define signum(operand) _Generic( (operand), \
unsigned long long: __signum_i4, unsigned long: __signum_i3, unsigned int: __signum_i2, unsigned short: __signum_i1, unsigned char: __signum_i0, \
signed long long: __signum_i4, signed long: __signum_i3, signed int: __signum_i2, signed short: __signum_i1, signed char: __signum_i0, \
long double: __signum_f2, double: __signum_f1, float: __signum_f0, \
complex long double: __signum_c2, complex double: __signum_c1, complex float: __signum_c0 \
) (operand)
They seem to work nicely, but for analytic reasons I'd like to create preprocessed source for some test cases so I can verify that the compiler chose the expected generics replacements. 它们似乎运行良好,但出于分析原因,我想为某些测试用例创建预处理源,以便我可以验证编译器是否选择了预期的泛型替换。 However, when using gcc -EI get half-expanded output like this: 但是,当使用gcc -EI获得半扩展输出时,如下所示:
assert(_Generic( (0LL), unsigned long long: __signum_i4, unsigned long: __signum_i3, unsigned int: __signum_i2, unsigned short: __signum_i1, unsigned char: __signum_i0, signed long long: __signum_i4, signed long: __signum_i3, signed int: __signum_i2, signed short: __signum_i1, signed char: __signum_i0, long double: __signum_f2, double: __signum_f1, float: __signum_f0, _Complex long double: __signum_c2, _Complex double: __signum_c1, _Complex float: __signum_c0 ) (0LL) == 0);
assert(_Generic( (+1LL), unsigned long long: __signum_i4, unsigned long: __signum_i3, unsigned int: __signum_i2, unsigned short: __signum_i1, unsigned char: __signum_i0, signed long long: __signum_i4, signed long: __signum_i3, signed int: __signum_i2, signed short: __signum_i1, signed char: __signum_i0, long double: __signum_f2, double: __signum_f1, float: __signum_f0, _Complex long double: __signum_c2, _Complex double: __signum_c1, _Complex float: __signum_c0 ) (+1LL) == +1);
...
I am assuming that _Generic is a preprocessor feature, and therefore expected the generic macros to be fully expanded like this: 我假设_Generic是一个预处理器功能,因此期望通用宏像这样完全展开:
assert(__signum_i4(0LL) == 0);
assert(__signum_i4(+1LL) == +1);
assert(__signum_i4(-1LL) == -1);
...
Is there any way to achieve this using a gcc flag? 有没有办法用gcc标志来实现这个目的?
I am assuming that _Generic is a preprocessor feature 我假设_Generic是一个预处理器功能
It's actually not, as described in the C11 draft , it's a primary-expression
, (as is an identifier
or a string literal
). 实际上,正如C11草案中所描述的那样,它不是primary-expression
(如identifier
或string literal
)。 So it's handled by the C compiler and not the pre-processor. 所以它由C编译器而不是预处理器处理。
Regarding the second part of the question: 关于问题的第二部分:
Is there any way to achieve this using a gcc flag? 有没有办法用gcc标志来实现这个目的?
You can dump the GIMPLE
tree, which is an intermediate representation after the C has been parsed, which will get you something approaching what you're looking for: 您可以转储GIMPLE
树,这是解析C之后的中间表示,它将为您提供接近您正在寻找的内容:
#include <math.h>
#include <stdio.h>
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
int main(void)
{
long double a = 0.0;
printf("%e\n", cbrt(a));
return 0;
}
Then: 然后:
$ gcc -c -fdump-tree-gimple main.c
Which results in: 结果如下:
main ()
{
long double D.3241;
int D.3242;
long double a;
a = 0.0;
D.3241 = cbrtl (a);
printf ("%e\n", D.3241);
D.3242 = 0;
return D.3242;
}
_Generic (C11, 6.5.1.1) apparently requires information about the type of the controlling expression . _Generic(C11,6.5.1.1)显然需要有关控制表达式类型的信息。 This obviously is only provided by the compiler, not the preprocessor. 这显然只是由编译器提供,而不是由预处理器提供。 So it is part of the compiler (6.5.1 - primary-expression). 所以它是编译器的一部分(6.5.1 - primary-expression)。
I somewhat wonder why this is called a preprocessor feature (not just by you, but may sites!). 我有点想知道为什么这被称为预处理器功能(不只是由你,但可能是网站!)。 I suppose as it just makes sense in a macro, as in normal functions the types are already known. 我想,因为它在宏中是有意义的,就像在普通函数中一样,类型已经是已知的。
Sidenote (not relevant for the code shown, but important): There may be only one of compatible types in the association list . 旁注(与显示的代码无关,但很重要): 关联列表中可能只有一种兼容类型 。 It will not distinguish between - for instance - int
and typdef int MyInt;
它不会区分 - 例如 - int
和typdef int MyInt;
or const int
(actually only at most one is allowed, 6.5.1.1/constraint 2). 或const int
(实际上只允许最多一个,6.5.1.1/constraint 2)。
I am assuming that _Generic is a preprocessor feature ... 我假设_Generic是一个预处理器功能......
It isn't. 事实并非如此。 It's treated as an operator , and is documented in section 6.5.1.1 of the C11 standard Section 6.5.1 indicates that a generic-selection is a kind of primary-expression . 它被视为一个运算符 ,并在C11标准的第6.5.1.1节中有记录。第6.5.1节指出泛型选择是一种主表达式 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.