Почему выравнивание длинного длинного члена объединения больше, чем содержащее объединение / структура? Это правильно?
Из этого вопроса можно было бы начать полагать, что выравнивание союза не меньше, чем наибольшее выравнивание его отдельных членов. Но у меня есть проблема с 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:
Мой отчет об ошибке был закрыт как дубликат предыдущего. Я буду просить разъяснений.