2016-07-25 53 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规范中),它只是方便的实现细节。 –