В примере, почему размер char _Alignas(double) не равен 8?
#include <stdio.h>
int main(void)
{
char c1 = '0';
char _Alignas(double) c2 = '0';
printf("char alignment: %zd\n", _Alignof(char));
printf("double alignment: %zd\n", _Alignof(double));
printf("&c1: %p\n", &c1);
printf("&c2: %p\n", &c2);
return 0;
}
Запуск в моей среде, результат:
char alignment: 1
double alignment: 8
&c1: 000000000061FE1F
&c2: 000000000061FE18
Скомпилировано gcc версии 8.1.0 (x86_64-posix-seh-rev0, построено проектом MinGW-W64).
Интересно, почему количество байтов между
&c2
а также
&c1
равно 7, а не 8 (
sizeof(double)
в моем окружении)?
2 ответа
почему двойной размер char _Alignas не равен 8?
Выравнивание означает, что адрес кратен некоторому значению. Это не имеет ничего общего с размером переменной.
_Alignas(8)
означает, что адрес будет кратен 8, то есть оканчивается на 0 или 8 в шестнадцатеричной системе счисления.
Интересно, почему байты между & c2 и & c1 равны 7, а не 8 (sizeof double в моей среде)?
Положение переменных в стеке не указано. Компилятор может свободно ставить до или после. Единственное требование здесь - выравнивание, которое должно быть кратно 8. Если оно кратно 8, и компилятор выбирает поставить сразу после этого, то будут использоваться 7 байтов заполнения. Но они, очевидно, могут поставить
c1
прямо перед
c2
и их адреса будут отличаться только на 1. Вы можете легко увидеть, что каждый компилятор помещает переменные в разные позиции с разным расстоянием.
Подробнее читайте
Выравнивание определяет, где будут находиться адреса, а не сколько места они займут.
A занимает только 1 байт, даже если он выровнен по 8-байтовой границе. Между c1 и c2 есть 6 неиспользуемых байтов.
Часто выравнивание и размер будут одинаковыми или выравнивание округляется до степени 2. Это потому, что на многих архитектурах может потребоваться несколько инструкций FETCH для извлечения из невыровненного адреса памяти.
В твоем случае,
c1
выравнивается по 1-байтовой границе, поэтому он помещается в первую доступную позицию в стеке.
выровнен по 8-байтовой границе, поэтому он пропускает необходимое количество байтов, пока адрес не будет выровнен по 8-байтовой границе. Это означает (адрес% 8) == 0. Если
c2
были типа
double
, потребуется перейти к следующему выровненному адресу на 8 байт впереди, но поскольку это всего лишь
char
он отлично вписывается в первую 8-байтовую границу.
Выравнивание может быть больше или меньше размера элемента.
В некоторых архитектурах вам просто нужно было выровнять по 2- или 4-байтовым границам. Компьютеры просто не могли адресовать «промежуточные байты». Адресные строки не нужны, поэтому вы можете адресовать 2 ^16 байтов памяти, используя только 14 адресных строк, если вы выравниваете по 4-байтовым адресам (и всегда читаете 4 байта). Это может уменьшить размер, необходимый для шины памяти.