2016-07-25 96 views
6

我想知道下面的C碼是否粘附在C99和/或C11標準(多個):通過使用指針來通過函數的參數迭代第一個

void foo(int bar0, int bar1, int bar2) { 
    int *bars = &bar0; 

    printf("0: %d\n1: %d\n2: %d\n", bars[0], bars[1], bars[2]); 
} 

int main(int argc, char **argv) { 
    foo(8, 32, 4); 

    return 0; 
} 

此代碼段編譯並運行使用視覺工作室2013和打印時如預期:

0:8
1:32
2:4

+1

你是想要滿足你的好奇心,還是你有一個你認爲會解決的問題? – StoryTeller

+0

出於好奇,因爲可變參數似乎使用這種技術來迭代它的參數。 –

回答

11

不,不是任何地方附近。

C標準不保證函數參數存儲在連續的存儲器位置(或任何特定順序,對於該事項)。編譯器和/或平臺(體系結構)決定如何將函數參數傳遞給函數。

爲了增加一些更清晰的內容,甚至不能保證將要傳遞的參數存儲在存儲器(例如堆棧)中。他們也可以利用硬件寄存器(,只要適用),對於一些的所有參數,使操作更快。例如,

  • 的PowerPC

    PowerPC架構具有大量的寄存器所以大多數功能都可以通過所有參數在用於單級調用寄存器。 [...]

  • MIPS

    32位MIPS最常用的調用約定是O32 ABI,其通過第一四個參數在寄存器的功能$a0 - $a3;隨後的參數在棧上傳遞。 [...]

  • X86

    x86架構用於許多不同的調用約定。由於體系結構寄存器的數量很少,x86調用約定主要在堆棧上傳遞參數,而返回值(或指向它的指針)則傳遞到寄存器中。

等等。檢查full wiki article here

所以,你的情況,bars[0]有效訪問,但bars[1]bars[2]是否有效,取決於基礎環境(平臺/編譯)完全。最好不要依賴你期望的行爲。

這就是說,只是雞蛋裏挑骨頭,如果你不打算使用的參數(如有)傳遞給main(),你可以簡單地簽名減少int main(void) {

+0

+1,但也許應該補充一點,在現代體系結構中,第一個函數參數根本不存儲在內存中,而是通過硬件寄存器。也許這也不是編譯器決定的,而是平臺API。 –

+0

@JensGustedt先生,在這方面增加了一些信息。現在好了嗎? –

5

沒有標準支持。這是非常調皮。

數組索引和指針算術只對數組有效。 (注意:一個小小的例外:你可以閱讀過去一個數組或一個標量的指針之一,但你不能尊重吧)

7

不,它不符合任何公佈的標準。參數和局部變量如何存儲以及在何處取決於編譯器。在一個編譯器中可能工作的內容可能不適用於另一個編譯器,甚至不適用於同一編譯器的不同版本。

C規範甚至沒有提到堆棧,它所指定的全部都是範圍規則。

+0

變量函數似乎也是標準的一部分 - va_start,va_end是標準庫的一部分,這正是這些宏正在做的 - 遍歷堆棧參數。 – MichaelMoser

+3

@MichaelMoser是的,但是如何實現這些宏不在標準中。有一個堆棧並不是C編譯器的要求(特別是因爲它不在C規範中),它只是方便的實現細節。 –