2009-08-29 59 views
4

嗨,宏问题

有人能帮我理解为什么SQUARE(x)的值是49吗?

我正在使用Visual C++ 6.0。

#define SQUARE(X) X * X 

int main(int argc, char* argv[]) 
{ 
    int y = 5; 

    printf("%d\n",SQUARE(++y)); 
    return 0; 
} 
+1

啊,这个老栗子......要得到你应该使用的正确结果:#define SQUARE(X)((X)*(X))。 – 2009-08-29 10:28:16

+5

@我错了,恐怕。 – 2009-08-29 10:32:56

+6

Ian Kemp的评论确实是错误的,因为它没有解决问题。但是,在宏中,更好的方法是添加括号:SQUARE(a + b)扩展为不是(a + b)*(a + b)的a + b * a + b,而是a +(b * a)+ b。 – moala 2009-08-29 11:02:18

回答

15

尼尔巴特沃斯,马克和帕维尔是正确的。

SQUARE(++ y)扩展为++ y * ++ y,它将y的值增加两倍。 (a + b)不是(a + b)*(a + b),而是a +(b * a)+ b扩展到a + b * a + b。在定义宏时,您应该注意在需要时在元素周围添加括号:#define SQUARE(X)((X)*(X))风险较小。 (伊恩·肯普在他的评论中第一次写的)

你也可以使用内联模板函数(没有在运行时效率较低),像这样的:

template <class T> 
inline T square(T value) 
{ 
    return value*value; 
} 

您可以检查它的工作原理:

int i = 2; 
std::cout << square(++i) << " should be 9" << std::endl; 
std::cout << square(++i) << " should be 16" << std::endl; 

(没有必要写

square<int>(++i) 

因为int类型是隐含的对于i)

+1

你在哪里写过“不需要写'square(++ i)'”我认为你的意思是“不需要写'方块(++ i)'”;如果你有*写入,你需要使用反引号来防止''被解释为html标签。 – dave4420 2009-08-29 11:04:54

+0

@Dave Hinton:谢谢,我没有看到它没有呈现。 – moala 2009-08-29 11:14:04

+0

总是很好提供一个体面的替代品! +1 – xtofl 2009-08-29 11:57:16

14

因为宏展开:

++y * ++y 

,其给出了C++未定义行为 - 其结果可能 是任何东西。这个众所周知的问题应该涵盖任何涵盖宏使用的正派教科书。你在使用哪一个?

+0

你也可以看到6x7 = 42,这取决于你的编译器。 – 2009-08-29 10:21:24

+0

@愿意 - 或者你可能没有得到42. – 2009-08-29 21:26:48

4

因为宏做文本替换,所以你写的代码被扩大到

printf("%d\n",++y * ++y); 

,然后操作的顺序是不确定的行为,使这个编译器看到2个增量,然后乘

所以要谨慎使用宏,以便使用函数,因为编译器可以扩展内联,不再需要运行。

其次不要以为你增加会发生什么,并使用变量

5

宏不是函数:他们只是改变了程序的文本。该操作被称为预处理,并且在编译代码之前它会自动执行。人们编写宏以节省时间并在源代码中引入一些可变性。

当您编写SQUARE(x)时,不会发生实际的功能调用,只是文本被修改。操作非常笨拙,所以你必须在像你这样的情况下采取额外的预防措施。请参阅其他答案以解释您的案例。