Я заметил кое-что странное после компиляции этого кода на моей машине:
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
int a,b,c,d;
int e,f,g;
long int h;
printf("The addresses are:\n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x",
&a,&b,&c,&d,&e,&f,&g,&h);
return 0;
}
Результат следующий. Обратите внимание, что между каждым адресом int существует 4-байтовая разница. Однако между последним int и длинным int существует 12-байтовая разница:
Hello, World!
The addresses are:
da54dcac
da54dca8
da54dca4
da54dca0
da54dc9c
da54dc98
da54dc94
da54dc88
int
послеh
в исходном коде. Компилятор может поместить это в пробел, преждеh
.sizeof
функция.printf("size: %d ", sizeof(long));
%x
. К счастью для вас, на вашей платформе правильно работает передача аргументов указателя с ожидаемой форматной строкойunsigned int
, но указатели и целые числа имеют разные размеры во многих ABI. Используйте%p
для печати указателей в переносимом коде. (Легко представить систему, в которой ваш код печатал бы верхнюю / нижнюю половину первых 4 указателей, а не нижнюю половину всех 8).%zu
. @yoyo_fun для распечатки адресов%p
. Использование неправильного спецификатора формата вызывает неопределенное поведениеОтветы:
Это не заняло 12 байтов, это только заняло 8. Тем не менее, выравнивание по умолчанию для int длиной 8 байтов на этой платформе составляет 8 байтов. Таким образом, компилятору нужно было переместить long int на адрес, который делится на 8. «Очевидный» адрес, da54dc8c, не делится на 8, следовательно, 12-байтовый пробел.
Вы должны быть в состоянии проверить это. Если вы добавите еще один int до long, то есть их будет 8, вы должны обнаружить, что long int будет выровнен нормально, без движения. Теперь это будет только 8 байтов от предыдущего адреса.
Вероятно, стоит отметить, что, хотя этот тест должен работать, вы не должны полагаться на переменные, организованные таким образом. Компилятору переменного тока разрешается делать все что угодно, чтобы заставить вашу программу работать быстро, включая переупорядочивание переменных (с некоторыми оговорками).
источник
Это связано с тем, что ваш компилятор генерирует дополнительное заполнение между переменными, чтобы гарантировать их правильное выравнивание в памяти.
На большинстве современных процессоров, если значение имеет адрес, кратный его размеру, доступ к нему более эффективен. Если бы он поставил
h
на первое доступное место, его адрес был бы 0xda54dc8c, который не кратен 8, поэтому был бы менее эффективным в использовании. Компилятор знает об этом и добавляет немного неиспользуемого пространства между двумя последними переменными, чтобы убедиться, что это произойдет.источник
Ваш тест не обязательно проверяет, что вы думаете, потому что язык не требует соотношения адреса любой из этих локальных переменных друг с другом.
Вы должны будете поместить их как поля в структуру, чтобы иметь возможность сделать вывод о распределении памяти.
Локальные переменные не обязаны совместно использовать хранилище друг с другом каким-либо конкретным образом. Например, компилятор может вставить временную переменную в любом месте стека, которая может находиться между любыми двумя из этих локальных переменных.
Напротив, было бы запрещено вставлять временную переменную в структуру, поэтому, если вместо этого вы напечатали адреса полей структуры, вы бы сравнили элементы, предназначенные для выделения из одного и того же логического фрагмента памяти (структуры).
источник