Почему адреса arg c и argv 12 байтов разделены? - PullRequest
40 голосов
/ 08 февраля 2020

Я запустил следующую программу на моем компьютере (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-байтовые отступы. Почему это так?

Я предполагаю, что это может быть связано с выравниванием памяти, но я не уверен.

Я замечаю такое же поведение и с функциями, которые я вызываю.

Ответы [ 2 ]

61 голосов
/ 08 февраля 2020

В вашей системе первые несколько целочисленных или указательных аргументов передаются в регистрах и не имеют адресов. Когда вы берете их адреса с &argc или &argv, компилятор должен сфабриковать адреса, записав содержимое регистра в ячейки стека и сообщив вам адреса этих расположений стека. При этом компилятор выбирает, в каком-то смысле, те места стека, которые ему подходят.

10 голосов
/ 08 февраля 2020

Почему адреса arg c и argv 12 байтов разнесены?

С точки зрения языкового стандарта ответом является «без особой причины». C не указывает и не подразумевает какую-либо связь между адресами параметров функции. @EricPostpischil описывает, что, вероятно, происходит в вашей конкретной реализации, но эти детали будут другими для реализации, в которой все аргументы передаются в стек, и это не единственная альтернатива.

Более того, я возникли проблемы с поиском способа, которым такая информация могла бы быть полезной в программе. Например, даже если вы «знаете», что адрес argv составляет 12 байтов перед адресом argc, все равно не существует определенного способа вычисления одного из этих указателей из другого.

...