Где я могу найти документацию по выравниванию памяти C++ на разных платформах/компиляторах?

Я ищу хороший (всеобъемлющий) документ о выравнивании памяти в C++, типичных подходах, различиях между компиляторами и распространенных ловушках. Просто чтобы проверить правильность моего понимания темы и узнать что-то новое.

Этот вопрос вдохновлен моим ответом на другой вопрос, где я использовал следующую конструкцию:

char const buf[1000] = ...;
unsigned int i = *reinterpret_cast<unsigned int*>(buf + shift); // shift can be anything

Его критиковали за несоответствие правилам выравнивания памяти. Не могли бы вы объяснить в качестве бонуса, почему этот подход ошибочен с точки зрения выравнивания памяти? Пример, когда это не работает, будет высоко оценен. Я знаю, что в целом это плохой подход, но я часто использую его в реализациях сетевых протоколов, так что это скорее практический вопрос, чем теоретический.

Также, пожалуйста, не упоминайте здесь строгие псевдонимы, это для другого вопроса.


person Andriy Tylychko    schedule 06.09.2011    source источник
comment
Разве сдвиг не кратен размеру слова вашей системы? Вас могли раскритиковать за попытку получить указатель в середине слова (скажем, в середине 32-битного слова), что было бы странно.   -  person Doug T.    schedule 06.09.2011
comment
даже если сдвиг был кратен 4, нет гарантии, что buf начнется с адреса, кратного 4   -  person nos    schedule 06.09.2011
comment
shift может быть что угодно, обновил вопрос   -  person Andriy Tylychko    schedule 06.09.2011
comment
Я просто хотел бы отметить здесь, что многие компиляторы имеют - как нестандартное расширение - директивы выравнивания, которые можно использовать для установки выравнивания структур на 1 - оберните ваш int в структуру с выравниванием по 1, и вы действительно можете разыменовать при любом смещении безопасно. Возникающие накладные расходы зависят от архитектуры вашего процессора; на x86 это не должно быть слишком болезненно.   -  person bdonlan    schedule 06.09.2011


Ответы (3)


Обзор можно найти в википедии. Подробнее на сайте IBM: Выравнивание данных: выпрямляйтесь и летите правильно

person Community    schedule 06.09.2011

Массивы char, не распределенные в куче, не имеют особых требований к их выравниванию. Таким образом, ваш буфер из тысячи символов может иметь нечетное смещение. Попытка прочитать int из этого смещения (переосмысленного как очевидный указатель int) приведет либо к снижению производительности, либо даже к ошибке шины на некотором оборудовании, если компилятор не разделит его на отдельные операции чтения + битовой маски.

Распределенные в куче массивы char гарантированно будут выровнены надлежащим образом для хранения объектов любого типа, так что это всегда вариант.

Для хранилища без кучи используйте boost::aligned_storage, что гарантирует правильное выравнивание пространства для общего использования.

person Mark B    schedule 06.09.2011
comment
+1: к сожалению, я не могу принять два ответа, поэтому я должен принять другой, который ответил на главный вопрос - person Andriy Tylychko; 06.09.2011

Представьте себе случай, когда адреса должны быть выровнены по 16 байтам, как, например, в PS3. А затем представьте, что сдвиг == 1. Тогда это наверняка будет не 16-байтовый выровненный указатель, который не будет работать на этой машине.

person Roel Van Nyen    schedule 06.09.2011