可以将三元运算符扩展为C宏中的if-else语句吗?

时间:2012-01-08 09:29:41

标签: c

  

定义一个宏MAX3,它给出最多三个值。

这就是我提出的:

#define MAX3(a,b,c) ( ((a) > (b)) && ((a) > (c)) ) ? (a) : ((b) > (c)) ? (b) : (c)

这很难读。有没有办法用if-else语句编写等效的宏?

2 个答案:

答案 0 :(得分:6)

在标准C99语言中,不能使用带有语句的类似表达式的宏(因为在C99语句和表达式中,语法和语义都有很大差异。)

但是,GCC(以及其他一些受GCC启发的扩展程序的编译器,例如clang)为此提供了一个很好的扩展:statement expressions(文档提供了与您的问题相关的示例)。使用该扩展,您可以编写类似

的代码
 #define MAX3(A,B,C) ({ int a=(A); int b=(B); int c=(C); int m; \
     if (a>b) m=a; else m=b;                                    \
     if (c>m) m=c;                                              \
     m; }) /* bad macro */
但是,如果您使用该宏,例如仍然无法工作

 int badex(int x, int y) { 
    int a= x+y; int m= x*y; int d=x-y; 
    return MAX3(a,m,d);
 }

我希望你明白为什么它不会工作(例如在a内部badexa内部MAX3宏之间发生冲突。所以你需要一种方法在每次调用宏时都有唯一的名称。同样,GCC为此提供了一个很好的扩展,__COUNTER__宏(扩展为一个唯一的数字,计数)与预处理器中的concatenation一起使用。

然后您将编写类似

的代码
 #define MAX3(A,B,C) MAX3_COUNTED((A),(B),(C),__COUNTER__)
 #define MAX3_COUNTED(A,B,C,N)  ({                          \
    int a_##N=(A); int b_##N=(B); int c_##N=(C);            \
    int m_##N;                                              \
    if (a_##N>b_##N) m_##N = a_##N; else m_#N = b_##N;      \
    if (c_##N>m_##N) m_##N=c_##N;                           \
  m_##N; }) /* better example */

然后第一次调用我们的宏,例如MAX3(i++,j++,k++)可能会扩展为MAX3_COUNTED((i++),(j++),(k++),1),并使用a_1 b_1扩展为某些内容...以及第二次调用,例如展开MAX3(a,m,d) MAX3_COUNTED((a),(m),(d),2)会使用a_2 b_2等,因此效果会更好。

当然,定义static inline max3(int a, int b, int c)函数更清晰(特别是因为副作用:您的MAX3宏会通过MAX3(i++,j++,k++)之类的调用提供顽皮的效果和结果

关于这一点的一般教训是,你应尽可能避免使用宏(更喜欢内联函数),当你绝对需要宏时,请注意名称冲突和扩展。

使用作为gcc -C -E调用的GCC向您显示程序的预处理形式。

答案 1 :(得分:3)

这样做可能会更好:

#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MAX3(a, b, c) MAX(a, MAX(b, c))

或者更好的是,使用内联函数而不是诉诸旧skool preprocesser滥用:

inline int max3(int a, int, int c) { return max(a, max(b, c)); }

它比宏更健壮,效率更高。