gcc -E不会展开C11 _Generic表达式 [英] gcc -E does not expand C11 _Generic expressions
问题描述
#define signum(操作数)_Generic((操作数),\
unsigned long long:__signum_i4,unsigned long:__signum_i3,unsigned int:__signum_i2,unsigned short:__signum_i1,unsigned char:__signum_i0,\
长签名long:__signum_i4,签名long:__signum_i3,signed int:__signum_i2,签名short:__signum_i1,signed char:__signum_i0,\
long double:__signum_f2,double:__signum_f1,float:__signum_f0,\
复合长双:__signum_c2,复数双:__signum_c1,复数浮点数:__signum_c0 \
)(操作数)
它们似乎很好地工作,但出于分析原因,我想为某些测试用例创建预处理源,以便我可以验证编译器是否选择了预期的泛型替换。然而,当使用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,有符号长long:__signum_i4,有符号long:__signum_i3,有符号int:__signum_i2,有符号短符号:__signum_i1,有符号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,long long:__signum_i4,signed long:__signum_i3, signed int:__signum_i2,__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);
...
我假设_Generic是预处理器功能,因此预计泛型宏需要像这样完全展开:
assert(__ signum_i4(0LL)== 0);
assert(__ signum_i4(+ 1LL)== +1);
assert(__ signum_i4(-1LL)== -1);
...
有没有办法通过gcc标志来实现这个功能? p>
我假设_Generic是一个预处理器功能
实际上并非如 C11草案,它是 primary-expression
,(如字符串文字
)。所以它由C编译器处理,而不是预处理器。
关于问题的第二部分:
< blockquote>
有什么办法可以使用gcc标志来实现这个功能吗?
您可以转储 GIMPLE
树,这是C语言被解析后的一个中间表示,它可以帮助你找到你要找的东西:
#include
#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 \\\
,cbrt(a));
返回0;
}
然后:
$ gcc -c -fdump-tree-gimple main.c
结果如下:
main()
{
long double D.3241;
int D.3242;
long double a;
a = 0.0;
D.3241 = cbrtl(a);
printf(%e \\\
,D.3241);
D.3242 = 0;
返回D.3242;
}
In a C11 library project I have a couple of macro functions that are exposed under a shared macro name using generics, like this:
#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 -E I get half-expanded output like this:
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:
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?
I am assuming that _Generic is a preprocessor feature
It's actually not, as described in the C11 draft, it's a primary-expression
, (as is an identifier
or a string literal
). So it's handled by the C compiler and not the pre-processor.
Regarding the second part of the question:
Is there any way to achieve this using a gcc flag?
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:
#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;
}
这篇关于gcc -E不会展开C11 _Generic表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!