2009-08-29 90 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)時,不會發生實際的功能調用,只是文本被修改。操作非常笨拙,所以你必須在像你這樣的情況下采取額外的預防措施。請參閱其他答案以解釋您的案例。