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

Iterating through a function's arguments by using a pointer to the first one

我想知道以下 C 代码是否符合 C99 and/or 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;
}

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

0: 8
1: 32
2: 4

没有标准支持这个。真是太调皮了。

数组索引和指针运算仅对数组有效。 (请注意一个小例外:您可以 读取 一个指向数组或标量的指针,但不能 引用 它。)

不,不在附近。

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

为了更加清楚,甚至不能保证要传递的参数存储在内存中(例如,堆栈)。他们也可以利用硬件寄存器(只要适用),用于某些所有参数,以加快操作速度。例如,

  • PowerPC

    The PowerPC architecture has a large number of registers so most functions can pass all arguments in registers for single level calls. [...]

  • MIPS

    The most commonly used calling convention for 32 bit MIPS is the O32 ABI which passes the first four arguments to a function in the registers $a0-$a3; subsequent arguments are passed on the stack. [...]

  • X86

    The x86 architecture is used with many different calling conventions. Due to the small number of architectural registers, the x86 calling conventions mostly pass arguments on the stack, while the return value (or a pointer to it) is passed in a register.

等等。检查 full wiki article here.

因此,在您的情况下,bars[0] 有效的 访问权限,但是 bars[1]bars[2] 是否有效取决于底层 环境 (platform/compiler),完全。最好不要依赖您期望的行为。

也就是说,只是吹毛求疵,如果您不打算使用传递给 main() 的参数(if any),您可以简单地减少签名给 int main(void) {.

不,它不遵守任何已发布的标准。参数和局部变量如何存储以及存储在何处取决于编译器。在一个编译器中可能有效的东西在另一个编译器中可能无效,甚至在同一编译器的不同版本上也可能无效。

C 规范甚至没有提到堆栈,它指定的只是作用域规则。