gcc -E does not expand C11 _Generic expressions

心不动则不痛 提交于 2019-12-11 02:28:23

问题


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?


回答1:


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



回答2:


_Generic (C11, 6.5.1.1) apparently requires information about the type of the controlling expression. This obviously is only provided by the compiler, not the preprocessor. So it is part of the compiler (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; or const int (actually only at most one is allowed, 6.5.1.1/constraint 2).




回答3:


I am assuming that _Generic is a preprocessor feature ...

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.



来源:https://stackoverflow.com/questions/30471806/gcc-e-does-not-expand-c11-generic-expressions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!