Вопрос по memory-alignment, unions, g++, unsigned-long-long-int, c++ – Почему выравнивание длинного длинного члена объединения больше, чем содержащее объединение / структура? Это правильно?

8

Отэтот вопрос Можно было бы начать полагать, что выравнивание союза не меньше, чем наибольшее выравнивание его отдельных членов. Но у меня есть проблема с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

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

[UPDATE]

Согласно ответу Кейта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 в глобальных данных. Для локальной области я не могу проверить это, так как кажется, что компилятор свободен переставлять локальные данные - так что этот прием не работает. Можете ли вы прокомментировать это?

[/UPDATE]

gcc.gnu.org/bugzilla/show_bug.cgi?id=52023 ссылка на соответствующую ошибку gcc для _Alignof (C11). Marc Glisse
Я вижу то же самое в Red Hat, GCC 4.7.0 с-m32, ноnot с-m64 (все8с). BoBTFish

Ваш Ответ

1   ответ
7

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

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

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

Some machines never actually require alignment; they allow reference to any data type even at an odd address. For these machines, __alignof__ reports the smallest alignment that GCC will give the data type, usually as mandated by the target 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__, Но неопределенность определения затрудняет уверенность в том, что это действительно ошибка.Похоже, об этом не сообщалось.

Update :

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

этоболее раннее сообщение об ошибкеЗакрыто как «INVALID», аналогично, но оно не относится к выравниванию самой структуры.

Update 2 :

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

Большое спасибо за этоALIGNOF() намек. PiotrNycz
Однако этот макрос не работает для типов NonPOD, так как offsetof не работает с NonPOD (см.stackoverflow.com/questions/1129894/…). Вы случайно не знаете решение для не-POD типов? PiotrNycz
@PiotrNycz: это сложно; объект, который выровнен с 8 байтами, также выровнен с 4 байтами, таким образом показывая, чтоlong long объект имеет 8-байтовый выровненный адрес, не демонстрирующий, что его выравнивание равно 8. Но дальнейший эксперимент показывает, что gccdoes кажется, выравниваниеlong long объекты на 8-байтовых границах иstruct { long long x; } объекты на 4-байтовых границах.
Можете ли вы прокомментировать мое обновление. Кажется, что__alignof__(long long)==8 верно. И что проверено с вашимALIGNOFэто просто выравниваниеlong long вstruct это тот же случай, что и мойstruct sll { long long m; }, Может быть, это поможет для вашего сообщения об ошибке. PiotrNycz

Похожие вопросы