2013-10-07 188 views
2

我試圖寫「現代」堆棧(帶有任何類型的數據)並且一次出錯。這是使用指針調用的函數的不正確參數數量。但是這在程序運行時不會造成任何問題。C:函數指針

所以這是測試的例子,工作絕對正確。

#include <stdio.h> 

int add(int a1, int a2) 
{ 
    return a1 + a2; 
} 

int main(void) 
{ 
    int (*pointer)() = add; 
    printf("12 + 13 = %d\n", pointer(12, 13, 123, 13, 21,3, 125, 234, 523)); 
    printf("12 + 14 = %d\n", pointer(12, 14, 123, 13, 21,3, 125, 234, 523)); 
    printf("12 + 15 = %d\n", pointer(12, 15, 123, 13, 21,3, 125, 234, 523)); 
    printf("12 + 16 = %d\n", pointer(12, 16, 123, 13, 21,3, 125, 234, 523)); 
    printf("12 + 17 = %d\n", pointer(12, 17, 123, 13, 21,3, 125, 234, 523)); 
    printf("12 + 18 = %d\n", pointer(12, 18, 123, 13, 21,3, 125, 234, 523)); 
    printf("12 + 19 = %d\n", pointer(12, 19, 123, 13, 21,3, 125, 234, 523)); 
    return 0; 
} 

據我瞭解,然後調用add函數,9個參數推入調用堆棧。但函數add()只使用其中的兩個。 爲什麼這樣的多次調用沒有像程序崩潰一樣的效果? (OS:在FreeBSD 9.1)

增加: 我改變代碼:

printf("12 + 13 = %d\n", pointer(12)); 
printf("12 + 13 = %d\n", pointer(13)); 
... 

編譯標誌:(版本4.6)-Wall -O4 tst_call.c GCC不產生警告,但輸出不正確:

$ gcc -Wall -O4 tst_call.c 
$ ./a.out 
12 + 13 = -10236 
12 + 14 = 12615693 
12 + 15 = 12615694 
12 + 16 = 12615695 
12 + 17 = 12615696 
12 + 18 = 12615697 
12 + 19 = 12615698 

gcc49(版本4.9)產生警告列表(警告: 'A2' 被用來在這個函數[-Wuninitialized]未初始化)。這裏輸出:

$ gcc49 -Wall -O4 tst_call.c 
$ ./a.out 
12 + 13 = 12 
12 + 14 = 13 
12 + 15 = 14 
12 + 16 = 15 
12 + 17 = 16 
12 + 18 = 17 
12 + 19 = 18 
+1

因爲C編譯器真的是寬容的,僅次於網頁瀏覽器 – UmNyobe

+0

「所以這是一個測試示例,它的工作原理絕對正確。」 - 不完全針對每個編譯器:gnu g ++編譯器報告OP代碼的錯誤。 –

+1

gun g ++是'C++'編譯器 – UmNyobe

回答

3

C中的傳統調用約定使調用者彈出了函數的所有參數。如果您推入了50個參數(不管使用的函數的數量如何),它仍然會彈出全部50個參數。

因此,無論參數推送數量與函數預期/使用的參數數量之間的不匹配如何,都會保留堆棧。當然,如果你推動參數少於功能預期的參數,事情可能不會很好。同樣,如果你設法得到一個不匹配的結果,例如,調用者這個函數認爲他們應該從堆棧中刪除參數,事情會變得很糟糕。

2

參數以相反的順序壓入堆棧。在這種情況下,您將指針指定爲無指定參數的函數,因此編譯器不會給9參數提供錯誤。當9參數通過時,add將正確看到前兩個參數(它們將按預期位於堆棧的開始處),因此它將正常執行前兩個參數。它會忽略其餘的參數。