В примере, почему размер 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 байта). Это может уменьшить размер, необходимый для шины памяти.

Другие вопросы по тегам