当我定义这个宏时:
#define SQR(x) x*x
让我们说这个表达式:
SQR(a+b)
此表达式将被宏替换,如下所示:
a+b*a+b
但是,如果我在表达式之前放置一个++
运算符:
++SQR(a+b)
现在的表情是什么样的?这个++
是否适用于SQR参数的每个部分?像这样:
++a+b*++a+b
这里我给出一个简单的程序:
#define SQR(x) x*x
int a, k = 3;
a = SQR(k+1) // 7
a = ++SQR(k+1) //9
答案 0 :(得分:5)
在定义宏时,你基本上总是想要将宏参数放在parens中以防止你的第一个例子中出现那种奇怪的行为,并将结果放在parens中以便安全使用副作用。使用
#define SQR(x) ((x)*(x))
将SQR(a+b)
扩展为((a+b)*(a+b))
,这在数学上是正确的(与a+b*a+b
不同,等于ab + a + b)。
在宏之前或之后放置内容不会进入宏。因此,++SQR(x)
在您的示例中变为++x*x
。
请注意以下事项:
int a=3, b=1;
SQR(a+b) // ==> a+b*a+b = 3+1*3+1 = 7
++SQR(a+b) // ==> ++a+b*a+b ==> 4 + 1*4 + 1 = 9
// since preincrement will affect the value of a before it is read.
你看到++SQR(a+b)
似乎增加了2,因为preincrement在a
之前开始读取时间,即a
增量,然后使用两次,因此结果高于预期值2。
注意正如@JonathanLeffler指出的那样,后一个调用会调用未定义的行为;评估不保证从左到右进行。它可能会在不同的编译器/操作系统上产生不同的结果,因此永远不应该依赖它。
答案 1 :(得分:1)
对于C ++,定义此宏的正确方法是不使用宏,而是使用:
template<typename T> static T SQR( T a ) { return a*a; }
这样可以解决一些宏观错误的可怕情况:
例如:
SQR(++a);
函数形式++a
的将被评估一次。在宏表单中,当您在序列点之间多次修改和读取值时,您会得到未定义的行为(至少对于C ++而言)
答案 2 :(得分:0)
宏定义只是替换代码,因此通常最好放入括号,否则代码可能会以您不想要的方式替换。
因此,如果您将其定义为:
#define SQR(x) ((x)*(x))
然后
++ SQR(a + b)= ++((a + b)*(a + b))
答案 3 :(得分:0)
在您的示例中,++SQR(a+b)
应扩展为++a+b*a+b
因此,如果a == 3且b == 1,如果编译器从左到右对其进行评估,您将得到答案9
。
但您的陈述++SQR(3+1)
不正确,因为它会被++3+1*3+1
扩展为++3
无效。
答案 4 :(得分:0)
在预处理器中,它的计算结果为++ a + b * a + b。正确的方法是在每个术语周围放置括号并围绕整个事项,例如:
#define SQR(x) ((x)*(x))