Function-like macro definition in C

2019-04-28 10:49发布

I'd like to define a function like MACRO . i.e.

#define foo(x)\
#if x>32\
 x\
#else\
 (2*x)\
#endif

that is,

if x>32, then foo(x) present x
else, foo(x) present (2*x)

but my GCC complains about:

int a = foo(31);

I think C preprocessor should be handle this correctly. since at compile time, it knows x=33. it could replace foo(33) with (2*33)

5条回答
贪生不怕死
2楼-- · 2019-04-28 10:49
#define \
    foo(x) \
    ({ \
        int xx = (x); \
        int result = (xx > 32) ? xx : (2*xx); \
        result; \
    })
查看更多
戒情不戒烟
3楼-- · 2019-04-28 10:53

You can as follows

#define foo(x) ((x) > 32 ? (x) : (2 * (x)))

But that evaluates x multiple times. You can instead create a static function, which is cleaner

static int foo(int x) {
  if(x > 32) 
    return x;
  return 2 * x;
}

Then you are also able to pass things to foo that have side effects, and have the side effect happen only one time.

What you have written is using the #if, #else and #endif preprocessor directives, but you need to use language constructs if you pass variables to the macro and want to evaluate their values. Using if, and else statements as in the actual language constructs don't work either, because control flow statements don't evaluate to values. In other words, an if statement is steering control flow only ("if A, then execute B, else execute C"), not evaluating to any values.

查看更多
▲ chillily
4楼-- · 2019-04-28 11:14

Consider:

int x = rand()
int y = foo( x );

x is not known at compile time.

查看更多
Anthone
5楼-- · 2019-04-28 11:14
int a = foo(31);

Expands out to

int a = if 31>32
31
else
(2*31)
endif;

That's how C macros work, via simple, dumb substitution. If you expect gcc to do anything more complex or intelligent with them, then your expectation is erroneous.

Given that, it's easy to see why your code won't work. An alternative that would suffice for this example would be:

#define foo(x) (x > 32 ? x : 2*x)

On the other hand, I would question whether macros are really the appropriate tool for such a thing to begin with. Just put it in the function and the compiler will inline the code if it thinks it will speed it up.

查看更多
甜甜的少女心
6楼-- · 2019-04-28 11:14

The problem is not about the theory: provided that you, for some reason, want to have a macro that expands differently according to the value of a parameter passed to it, and this parameter is a constant, known to the macro preprocessor, there's no reason why it couldn't work... for a generic macro processor... But cpp unluckly does not allow the presence of other macro processor "commands" into a macro definition...

So your

#define foo(x) \
#if x>32 \
  x      \
#else    \
  2*x    \
#endif

does not expand to

#if X>32
  X
#else
  2*X
#endif

where X is the known parameter (so change X to e.g. 31), which requires another pass by the preprocessor.

Moreover newlines are ignored, while they are important for such an use; otherwise, the following could be considered as a trick (that need another preprocessing pass however)

#define foo(x,y) \
y if x>32 \
  x  \
y else \ 
  2*x \
y endif

that with foo(20,#) produces

# if 20>32 20 # else 2*20 # endif

which would work, if it would be

# if 20>32
  20
# else
  2*20
# endif

... but it is not (and as said, the output of the preprocessor must be feeded to the preprocessor again...)

So my answer is that if you need these things, you can't use the C preprocessor; you should use a uncommon (not standard?) C preprocessor, or just another macro processor, and if you need the sort of things that "cpp" has to "integrate" itself with C, then you can't use a generic one (like M4) so easily...

查看更多
登录 后发表回答