为什么 argc 和 argv 的地址相隔 12 个字节?

Why are the addresses of argc and argv 12 bytes apart?

我 运行 我的电脑上有以下程序(64 位 Intel 运行 Linux)。

#include <stdio.h>

void test(int argc, char **argv) {
    printf("[test] Argc Pointer: %p\n", &argc);
    printf("[test] Argv Pointer: %p\n", &argv);
}

int main(int argc, char **argv) {
    printf("Argc Pointer: %p\n", &argc);
    printf("Argv Pointer: %p\n", &argv);
    printf("Size of &argc: %lu\n", sizeof (&argc));
    printf("Size of &argv: %lu\n", sizeof (&argv));
    test(argc, argv);
    return 0;
}

程序的输出是

$ gcc size.c -o size
$ ./size
Argc Pointer: 0x7fffd7000e4c
Argv Pointer: 0x7fffd7000e40
Size of &argc: 8
Size of &argv: 8
[test] Argc Pointer: 0x7fffd7000e2c
[test] Argv Pointer: 0x7fffd7000e20

指针的大小&argv是8个字节。我希望 argc 的地址是 address of (argv) + sizeof (argv) = 0x7ffed1a4c9f0 + 0x8 = 0x7ffed1a4c9f8 但它们之间有一个 4 字节的填充。为什么会这样?

我猜可能是内存对齐问题,但我不确定。

我注意到我调用的函数也有同样的行为。

在您的系统上,前几个整数或指针参数在寄存器中传递并且没有地址。当您使用 &argc&argv 获取它们的地址时,编译器必须通过将寄存器内容写入堆栈位置并为您提供这些堆栈位置的地址来伪造地址。在这样做的过程中,从某种意义上说,编译器会选择恰好适合它的任何堆栈位置。

Why are the addresses of argc and argv 12 bytes apart?

从语言标准来看,答案是"no particular reason"。 C 不指定或暗示函数参数地址之间的任何关系。 @EricPostpischil 描述了您的特定实现中可能发生的情况,但是对于所有参数都在堆栈上传递的实现,这些细节会有所不同,并且这不是唯一的选择。

此外,我在想出一种方法可以使此类信息在程序中有用时遇到了麻烦。例如,即使您 "know" argv 的地址比 argc 的地址早 12 个字节,仍然没有定义的方法来计算其中一个指针与另一个指针。