gcc -E不会展开C11 _Generic表达式 [英] gcc -E does not expand C11 _Generic expressions

查看:207
本文介绍了gcc -E不会展开C11 _Generic表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个C11库项目中,我使用泛型共享宏名称来暴露一些宏函数,如下所示:

  #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 ,(如 identifier 或字符串文字)。所以它由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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆