通过使用指向第一个参数的指针迭代函数的参数

Job*_*lle 6 c pointers c99 parameter-passing c11

我想知道以下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;
}
Run Code Online (Sandbox Code Playgroud)

在使用visual studio 2013并打印时,此代码段按预期编译和运行:

0:8
1:32
2:4

Sou*_*osh 11

不,不在附近.

C标准不保证函数参数存储在连续的内存位置(或者,任何特定的顺序,就此而言).由编译器和/或平台(体系结构)决定如何将函数参数传递给函数.

为了进一步增加清晰度,甚至不能保证要传递的参数存储在存储器(例如,堆栈)中.对于部分全部参数,他们也可以使用硬件寄存器(适用时),以便快速进行操作.例如,

  • PowerPC的

    PowerPC体系结构具有大量寄存器,因此大多数函数可以将寄存器中的所有参数传递给单级调用.[...]

  • MIPS

    最常用的32位MIPS调用约定是O32 ABI,它将前四个参数传递给寄存器中的函数$a0- $a3; 后续参数在堆栈上传递.[...]

  • X86

    x86体系结构与许多不同的调用约定一起使用.由于架构寄存器数量较少,x86调用约定主要在堆栈上传递参数,而返回值(或指向它的指针)在寄存器中传递.

等等.在这里查看完整的wiki文章.

所以,你的情况,bars[0]是一种有效的访问,但是否bars[1]bars[2]有效,取决于基础环境(平台/编译)完全.最好不要依赖你期望的行为.

也就是说,只是为了挑剔,如果你不打算使用传递的参数(如果有的话)main(),你可以简单地将签名减少到int main(void) {.


Som*_*ude 7

不,它不遵守任何已发布的标准.如何存储参数和局部变量,以及编译器的位置.在一个编译器中可能起作用的可能在另一个编译器中不起作用,或者甚至在同一编译器的不同版本上起作

C规范甚至没有提到堆栈,它指定的都是范围规则.

  • @MichaelMoser是的,但这些宏的实现方式不在标准中.并且堆栈不是C编译器的要求(特别是因为它不在C规范中),它只是方便的实现细节. (3认同)

Bat*_*eba 5

没有标准支持这一点.这非常顽皮.

数组索引和指针算法仅对数组有效.(注意一个小例外:你可以读取一个经过数组或标量的指针,但你不能将它推迟.)