Почему выравнивание длинного длинного члена объединения больше, чем содержащее объединение / структура? Это правильно?

Из этого вопроса можно было бы начать полагать, что выравнивание союза не меньше, чем наибольшее выравнивание его отдельных членов. Но у меня есть проблема с long long введите gcc/g++. Полный пример можно найти здесь, но вот соответствующие части для моего вопроса:

union ull {
  long long m;
};

struct sll {
  long long m;
};


int main() {
#define pr(v) cout << #v ": " << (v) << endl
   pr(sizeof(long long));
   pr(__alignof__(long long));
   pr(sizeof(ull));
   pr(__alignof__(ull));
   pr(sizeof(sll));
   pr(__alignof__(sll));
};

Это приводит к следующему выводу:

sizeof(long long): 8
__alignof__(long long): 8
sizeof(ull): 8
__alignof__(ull): 4
sizeof(sll): 8
__alignof__(sll): 4

Почему выравнивание члена профсоюза больше, чем у объединяющего союза?

[ОБНОВИТЬ]

Согласно ответу Кейта alignof здесь неверен. Но я проверяю следующее, и кажется, что alignof говорит нам правду. Увидеть:

union ull {
  long long m;
};
long long a;
char b;
long long c;
char d;
ull e;
int main() {
#define pr(v) cout << #v ": " << (v) << endl
   pr(size_t((void*)&b));
   pr(size_t((void*)&c));
   pr(size_t((void*)&d));
   pr(size_t((void*)&e));
   pr(size_t((void*)&c) - size_t((void*)&b));
   pr(size_t((void*)&e) - size_t((void*)&d));
};

Выход:

size_t((void*)&b): 134523840
size_t((void*)&c): 134523848
size_t((void*)&d): 134523856
size_t((void*)&e): 134523860
size_t((void*)&c) - size_t((void*)&b): 8
size_t((void*)&e) - size_t((void*)&d): 4

Итак, выравнивание long long 8 и выравнивание объединения, содержащего long long 4 в глобальных данных. Для локальной области я не могу проверить это, так как кажется, что компилятор свободен переставлять локальные данные - так что этот прием не работает. Можете ли вы прокомментировать это?

[/ОБНОВИТЬ]

1 ответ

Решение

__alignof__ (который является расширением gcc) не обязательно сообщает о требуемом выравнивании для типа.

Процессоры x86, например, на самом деле не требуют более 1-байтового выравнивания для любого типа. Доступ к 4-байтовому или 8-байтовому объекту, вероятно, будет более эффективным, если объект выровнен по словам, но байтового выравнивания достаточно.

Цитирование документации gcc:

Некоторые машины никогда не требуют выравнивания; они позволяют ссылаться на любой тип данных даже по нечетному адресу. Для этих машин __alignof__ сообщает о наименьшем выравнивании, которое GCC предоставит типу данных, обычно в соответствии с указаниями целевого ABI.

Но это все еще не отвечает на этот вопрос. Даже с таким свободным определением я не могу придумать ни одной веской причины __alignof__ чтобы указать более строгое выравнивание для long long чем для структуры или объединения, содержащего long long,

Более портативный метод определения выравнивания типа таков:

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t)))

Это дает смещение члена типа t в структуре, состоящей из char и t, Используя этот макрос, эта программа:

#include <iostream>
#include <cstddef>

union ull {
  long long m;
};

struct sll {
  long long m;
};

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t)))

int main() {
#define pr(v) std::cout << #v ": " << (v) << std::endl
   pr(sizeof(long long));
   pr(__alignof__(long long));
   pr(ALIGNOF(long long));
   pr(sizeof(ull));
   pr(__alignof__(ull));
   pr(ALIGNOF(ull));
   pr(sizeof(sll));
   pr(__alignof__(sll));
   pr(ALIGNOF(sll));
};

производит вывод на моей системе (gcc-4.7, Ubuntu 12.04, x86):

sizeof(long long): 8
__alignof__(long long): 8
ALIGNOF(long long): 4
sizeof(ull): 8
__alignof__(ull): 4
ALIGNOF(ull): 4
sizeof(sll): 8
__alignof__(sll): 4
ALIGNOF(sll): 4

Результаты, указанные моим ALIGNOF() макро согласованы: long long имеет 4-байтовое выравнивание и структуру или объединение, содержащее long long имеет 4-байтовое выравнивание.

Я подозреваю, что это ошибка или, по крайней мере, несоответствие в реализации gcc __alignof__, Но неопределенность определения затрудняет уверенность в том, что это действительно ошибка. Кажется, об этом не сообщалось.

Обновить:

Возможно, я прыгаю из пистолета, но я только что отправил отчет об ошибке.

Этот более ранний отчет об ошибках, закрытый как "INVALID", аналогичен, но он не относится к выравниванию самой структуры.

Обновление 2:

Мой отчет об ошибке был закрыт как дубликат предыдущего. Я буду просить разъяснений.

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