带参数的宏

And*_*rei 15 c

假设我使用参数定义宏,然后按如下方式调用它:

#define MIN(x,y) ((x)<(y)?(x):(y))
int x=1,y=2,z;
z=MIN(y,x);
Run Code Online (Sandbox Code Playgroud)

鉴于(a)宏作为文本替换,(b)这里的实际args就像正式args,只交换, - 这个特定的z = MIN(y,x)是否按预期工作?如果会的话,为什么?我的意思是,预处理器如何管理不混淆实际和正式的args?

这个问题是关于C编译器的技术问题.这不是c ++问题.
这个问题不建议任何人使用宏.
这个问题与编程风格无关.

zwo*_*wol 15

宏的内部表示将是这样的,其中空格表示标记边界,#1并且#2是魔术内部使用的标记,指示参数将被替换的位置:

MIN( #1 , #2 )  -->  ( ( #1 ) < ( #2 ) ? ( #1 ) : ( #2 ) )
Run Code Online (Sandbox Code Playgroud)

- 也就是说,预处理器内部没有使用宏参数的名称(除了实现有关重定义的规则).因此,形式参数名称与实际参数相同并不重要.

什么可以当宏体利用一个标识符的导致问题是不是一个正式的参数名称,但标识也出现在扩张形式参数.例如,如果您MIN使用GNU扩展重写了您的宏,那么您可以避免两次评估参数...

#define MIN(x, y) ({ \
    __typeof__(x) a = (x); \
    __typeof__(y) b = (y); \
    a < b ? a : b; \
})
Run Code Online (Sandbox Code Playgroud)

然后你试着像这样使用它:

int minint(int b, int a) { return MIN(b, a); }
Run Code Online (Sandbox Code Playgroud)

宏扩展看起来像这样:

int minint(int b, int a)
{
   return ({
       __typeof__(b) a = (b);
       __typeof__(a) b = (a);
       a < b ? a : b;
   });
}
Run Code Online (Sandbox Code Playgroud)

并且函数将始终返回其第一个参数,无论它是否更小.在一般情况下,C无法避免此问题,但许多人使用的约定是始终在宏中定义的每个局部变量的名称的末尾加上下划线,并且永远不会在任何末尾放置下划线.其他标识符.(对比Scheme的卫生宏的行为,保证没有这个问题.Common Lisp让你自己担心,但至少你必须gensym帮忙.)