let*_*utx 40 c memory-alignment
我在我的计算机(运行 Linux 的 64 位 Intel)上运行了以下程序。
#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;
}
Run Code Online (Sandbox Code Playgroud)
该程序的输出是
$ 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
Run Code Online (Sandbox Code Playgroud)
指针的大小&argv为 8 个字节。我期望的地址是argc,address of (argv) + sizeof (argv) = 0x7ffed1a4c9f0 + 0x8 = 0x7ffed1a4c9f8但它们之间有一个 4 字节的填充。为什么会这样?
我的猜测是这可能是由于内存对齐,但我不确定。
我注意到我调用的函数也有相同的行为。
Eri*_*hil 61
在您的系统上,前几个整数或指针参数在寄存器中传递并且没有地址。当您使用&argc或获取它们的地址时&argv,编译器必须通过将寄存器内容写入堆栈位置并为您提供这些堆栈位置的地址来制造地址。这样做时,从某种意义上说,编译器会选择任何适合它的堆栈位置。
Joh*_*ger 11
为什么 argc 和 argv 的地址相差 12 个字节?
从语言标准来看,答案是“没有特别的原因”。C 不指定或暗示函数参数地址之间的任何关系。@EricPostpischil 描述了您的特定实现中可能发生的情况,但是对于所有参数都在堆栈上传递的实现,这些细节会有所不同,这不是唯一的选择。
此外,我在想出一种方法可以使此类信息在程序中有用时遇到了麻烦。例如,即使您“知道” 的地址argv是 的地址之前 12 个字节argc,仍然没有定义的方法来计算这些指针中的一个。