Я запустил следующую программу на своем компьютере (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("Размер &argc: %lu\n", sizeof (&argc));
printf("Размер &argv: %lu\n", sizeof (&argv));
test(argc, argv);
return 0;
}
Вывод программы был следующим
$ gcc size.c -o size
$ ./size
Argc Указатель: 0x7fffd7000e4c
Argv Указатель: 0x7fffd7000e40
Размер &argc: 8
Размер &argv: 8
[тест] Указатель Argc: 0x7fffd7000e2c
[test] Argv Pointer: 0x7fffd7000e20
Размер указателя &argv
составляет 8 байт. Я ожидал, что адрес argc
будет address of (argv) + sizeof (argv) = 0x7ffed1a4c9f0 + 0x8 = 0x7ffed1a4c9f8
, но между ними находится 4-байтовая прокладка. Почему так происходит?
Я предполагаю, что это может быть связано с выравниванием памяти, но я не уверен.
Я замечаю такое же поведение и в функциях, которые я вызываю.
В вашей системе первые несколько целочисленных или указательных аргументов передаются в регистрах и не имеют адресов. Когда вы получаете их адреса с помощью &argc
или &argv
, компилятор вынужден создавать адреса, записывая содержимое регистров в места стека и передавая вам адреса этих мест. При этом компилятор выбирает, в некотором смысле, любое удобное для него расположение стека.
Почему адреса argc и argv находятся на расстоянии 12 байт друг от друга?
С точки зрения стандарта языка, ответ "без особых причин". Язык C не определяет и не подразумевает никакой связи между адресами параметров функций. @EricPostpischil описывает, что, вероятно, происходит в вашей конкретной реализации, но эти детали были бы другими для реализации, в которой все аргументы передаются в стеке, и это не единственная альтернатива.
Более того, мне трудно придумать, как такая информация может быть полезна в программе. Например, даже если вы "знаете", что адрес argv
находится на 12 байт раньше адреса argc
, все равно не существует определенного способа вычислить один из этих указателей по другому.