C 44 函式引數的秘密 (上)

2021-09-13 01:11:10 字數 2257 閱讀 5075

下面的程式輸出什麼?為什麼呢?

int k = 1;

printf("%d, %d\n", k++, k++);

#include int func(int i, int j)

int main()

輸出:【gcc】

i = 2, j = 1

3

特別說明:此處暫時沒有找到有其它求值順序的編譯器來輸出說明。

由於c語言未明確規定函式引數的求值順序,其交由具體的編譯器廠商決定,因此為了提高程式的可移植性,不可依賴某一編譯器的求值順序行為。

下面的程式執行結束後 k 的值為多少呢?

int k = 2;

k = k++ + k++;

實驗 1

#include int main()

return 0;

}

輸出【gcc】:

k = 6

輸出【vs2010】:

k = 6

vs2010 彙編

k = k++ + k ++;

003d356c mov eax,dword ptr [k]

003d356f add eax,dword ptr [k]

003d3572 mov dword ptr [k],eax ; k = 2 + 2 = 4

003d3575 mov ecx,dword ptr [k]

003d3578 add ecx,1

003d357b mov dword ptr [k],ecx ; k = k + 1 = 4 + 1 = 5

003d357e mov edx,dword ptr [k]

003d3581 add edx,1

003d3584 mov dword ptr [k],edx ; k = k + 1 = 4 + 1 = 6

gcc 彙編

int k = 2;

080483cd: movl $0x2,0x1c(%esp)

k = k++ + k ++;

080483dd: mov 0x1c(%esp),%eax

080483e1: add %eax,%eax

080483e3: mov %eax,0x1c(%esp) ; k = 2 + 2 = 4

080483e7: addl $0x1,0x1c(%esp) ; k = k + 1 = 4 + 1 = 5

080483ec: addl $0x1,0x1c(%esp) ; k = k + 1 = 5 + 1 = 6

實驗 2

#include int func(int i, int j)

int main()

輸出:【gcc】

i = 2, j = 1

3輸出:【用於 80x86 的 microsoft (r) 32 位 c/c++ 優化編譯器 16.00.30319.01 版】

i = 1, j = 1

3

分析:c 檔案會被編譯成彙編檔案。一條c**可能對應多條彙編**,彙編**的順序也許沒有特定的規定。對於不同的編譯器,可能有不同的編譯方式,但都必須滿足這一原則:在程式到達順序點時,所有改變記憶體的操作必須完成。

注意:

在實際工程中, 需要遵循一定的規則避免非 c 語言規定而與編譯器相關的寫法。

對於「函式引數的求值順序」、「程式中的順序點「不必過度深究,遇到奇怪的問題時,思考是否是這裡導致的問題即可。

第44課 函式引數的秘密(上)

1 函式引數在本質上與區域性變數相同,都在棧上分配空間 2 函式引數的初始值是函式呼叫時的實參值 3 c標準只規定了 必須要將每個實參的具體值求出來之後才能進行函式呼叫,並沒有規定函式引數的求值順序,求值順序依賴於編譯器的實現 比如void func 引數表示式1,引數表示式2,引數表示式3 這三個...

main函式引數的秘密

大家應該都有乙個模糊的記憶,c語言中main函式是程式的入口函式,所以程式執行時main函式呼叫別的函式,並且給別的函式傳入引數。但是沒人告訴我們是誰 呼叫 的main函式。其實我們可以理解為是作業系統呼叫的main函式,所以main函式的引數應該是作業系統給的,也就是說我們的在命令列介面執行程式是...

傳入引數個數 main函式引數的秘密

大家應該都有乙個模糊的記憶,c語言中main函式是程式的入口函式,所以程式執行時main函式呼叫別的函式,並且給別的函式傳入引數。但是沒人告訴我們是誰 呼叫 的main函式。其實我們可以理解為是作業系統呼叫的main函式,所以main函式的引數應該是作業系統給的,也就是說我們的在命令列介面執行程式是...