假设我使用参数定义宏,然后按如下方式调用它:
#define MIN(x,y) ((x)<(y)?(x):(y))
int x=1,y=2,z;
z=MIN(y,x);
鉴于(a)宏作为文本替换,(b)这里的实际args就像正式的args,只有交换, - 这个特定的z = MIN(y,x)是否按预期工作?如果会的话,为什么? 我的意思是,预处理器如何管理不要混淆实际和正式的args?
这个问题是关于 C编译器的技术性。这不是c ++问题 这个问题不建议任何人使用宏 这个问题与编程风格无关。
答案 0 :(得分:14)
宏的内部表示将是这样的,其中空格表示标记边界,#1
和#2
是魔术内部使用的标记,指示参数将被替换的位置:< / p>
MIN( #1 , #2 ) --> ( ( #1 ) < ( #2 ) ? ( #1 ) : ( #2 ) )
- 也就是说,预处理器内部没有使用宏参数的名称(除了实现有关重定义的规则)。因此,形式参数名称与实际参数相同并不重要。
可能导致问题的原因是当宏体使用不是正式参数名称的标识符时,该标识符也出现在中扩展的形式参数。例如,如果您使用GNU扩展重写了MIN
宏,可以避免两次评估参数......
#define MIN(x, y) ({ \
__typeof__(x) a = (x); \
__typeof__(y) b = (y); \
a < b ? a : b; \
})
然后你试图像这样使用它:
int minint(int b, int a) { return MIN(b, a); }
宏扩展看起来像这样:
int minint(int b, int a)
{
return ({
__typeof__(b) a = (b);
__typeof__(a) b = (a);
a < b ? a : b;
});
}
并且函数将始终返回其第一个参数,无论它是否更小。在一般情况下,C无法避免此问题,但许多人使用的约定是始终在宏内定义的每个局部变量的名称的末尾加上下划线,并且< em> never 将下划线放在任何其他标识符的末尾。 (对比Scheme的hygienic macros的行为,保证不会出现这个问题.Common Lisp让你自己担心,但至少你有gensym
来帮忙。)
答案 1 :(得分:4)
它将按预期工作。
#define MIN(x, y) ((x) < (y) ? (x) : (y))
int x=1,y=2,z;
z = MIN(y, x);
变为
int x=1,y=2,z;
z = ((y) < (x) ? (y) : (x));
以上是否有任何语法或语义错误?不会。因此,结果将符合预期。
答案 2 :(得分:2)
由于你错过了一个')',我认为它不会起作用。
编辑:
现在已经修复了,它应该可以正常工作。如果您的字符串x
中包含“x”,则y
和x
不会混淆。
答案 3 :(得分:0)
首先,这不是关于C编译器,这是关于C预处理器的。宏就像一个函数,就像文本替换一样。您使用的变量名称对宏替换的结果没有影响。你可以做到:
#define MIN(x,y) ((x)<(y)?(x):(y))
int blarg=1,bloort=2,z;
z=MIN(bloort,blarg);
并获得相同的结果。
答案 4 :(得分:0)
作为一个副节点,min()宏是使用宏时可能出错的完美示例,作为练习,您应该看到运行以下代码时会发生什么:
int x,y,z;
x=1;y=3;
z = min(++x,y);
printf("%d %d %d\n", x,y,z); /* we would expect to get 2 3 2, but we get 3 3 3 . */