Вопрос по struct, c – Почему отступы должны быть степенью двойки?

3

Я делаю несколько примеров программ для изучения C и хотел бы знать, почему заполнение структуры может быть сделано только в степени двух.

#include <stdio.h>

#pragma pack(push, 3)

union aaaa
{

   struct bbb
   {
      int a;
      double b;
      char c;
   }xx;

   float f;
};

#pragma pack(pop)

int main()
{

printf("\n Size: %d", sizeof(union aaaa));

return 0;
}

Во время компиляции

warning: alignment must be a small power of two, not 3 [-Wpragmas]
warning: #pragma pack (pop) encountered without matching #pragma pack (push) [-Wpragmas]

Кажется, #pragma не имеет никакого эффекта. Выход только 24. т.е. 4 байта выровнены.

Ваш Ответ

5   ответов
2

что существуют физические причины, по которым компьютерные конструкции предпочитают выравнивание памяти по степеням двух, еще одно не менее важное требование состоит в том, что все выравнивания памяти должны делиться равномерно на некоторое число. В противном случае, если, например, одна структура должна быть выровнена по кратному 7, одна должна быть выровнена по кратному 8, а одна должна быть выровнена по кратному 9, aunion содержащий все три структуры должен быть выровнен по кратному 504.

Обычный способ выполнения требования делимости состоит в том, чтобы сказать, что все размеры выравнивания должны подразделять некоторую большую степень двух. Такой подход будет работать, но он не будет единственно возможным осуществлением. Можно было бы, если бы кто-то был так склонен, проектировать аппаратные средства, которые работали бы со 120-байтовыми строками кэша и позволяли выравнивать объекты по кратным числам 2, 3, 4, 5, 6, 8, 10, 12, 15, 20. 24, 30, 40, 60 или 120 байтов. Такая конструкция может быть очень разумной с аппаратной точки зрения (каждая строка кэша будет храниться как 1024 бита, включая 64 бита с исправлением ошибок, тегами записи или другой информацией) и позволит эффективно хранить 80-битные реалы , Триплеты RGB или XYZ (любого числового типа, включая 80-битные реалы). Если бы не требовалось, чтобы физические адреса были в той же числовой последовательности, что и логические адреса, схема, требуемая для того, чтобы отобразить 120-байтовые диапазоны в строки кэша, не была бы слишком дорогой. С другой стороны, за пределами специализированных приложений маловероятно, что преимущества отображений, не являющихся степенями двух, были бы достаточными для преодоления проблем стоимости и инерции рынка.

8

руктурам, потому что процессоры работают быстрее на выровненных данных (и на некоторых архитектурах они вообще не работают на выровненных данных), а реквизиты выравнивания для различных типов данных всегда имеют небольшие степени двух (по крайней мере, на любой архитектуре, о которой я слышал).

Тем не менее, если по какой-то странной причине вам требуется произвольное выравнивание, ничто не мешает вам добавить пустышкуchar массивы в правильных местах для обеспечения вашего выравнивания (что в любом случае более или менее то, что компилятор делает под капотом).

Расскажи мне об этом. Пока я не понял, что m86k & # x201C; segfaulted & # x201D; из-за случайного смещения у меня появились первые седые волосы.
0

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html) используется прагма пакета «Для совместимости с компиляторами Microsoft Windows».

Если вы ищете документацию MS по выравниванию (http://msdn.microsoft.com/en-us/library/ms253949(v=vs.80).aspx) вы обнаружите, что компилятор MSVC обеспечивает выравнивание типов в зависимости от размера данных; который, как объясняют другие посты, являетсяlogically всегда степень 2.

Если ваша проблема заключается в том, что вам нужно какое-то причудливое выравнивание структуры данных (чтобы получить доступ к непонятным периферийным устройствам, отображенным в памяти), то вам лучше всего использоватьmanual упаковка структуры путем добавления полей, которые добавляют необходимые отступы.

3

и обычно она имеет ширину в два байта, поскольку это максимально эффективное использование битов в поле.

Трехбитное поле вроде так

[0][0][0]

имеет возможное представление восьми чисел

0, 1, 2, 3, 4, 5, 6, 7, and 8

Если вы ограничены номерами

0, 1, 2

Тогда вы будете тратить бит самого высокого порядка, который всегда будет равен нулю. Разработчикам аппаратного и программного обеспечения в первые дни вычислительной техники требовалось все, что они могли получить, потому что памятьvery expensiveТаким образом, этот вид отходов был разработан вне системы.

Позже, когда подсистемы памяти выросли, согласованный доступ стал дешевле проектировать. Выровненный доступ требует, чтобы начало элемента данных находилось на определенных границах, чтобы уменьшить количество передач по шине памяти и уменьшить количество вычислений в управлении шиной.

«Сила двух» требование было побочным эффектом архитектуры шины в сочетании с простой процедурой, которая гарантировала, что структуры данных C могут быть выровнены с выровненными границами доступа.

16

что базовые объекты в процессорах имеют размеры, которые имеют небольшую степень двух (например, 1, 2, 4, 8 и 16 байт), а память организована в группы, размер которых небольшой степени двух (например, 8 байты), поэтому структуры должны быть выровнены, чтобы хорошо работать с этими размерами.

Длинный ответ заключается в том, что причины этого основаны на физике и элементарной математике. Компьютеры, естественно, работают с битами со значениями 0 и 1. Это потому, что легко проектировать физические объекты, которые переключаются между двумя значениями: высокое напряжение и низкое напряжение, наличие заряда или отсутствие заряда и так далее. Различать три значения сложнее, потому что вы должны быть более чувствительными к переходам между значениями. Итак, поскольку компьютерные технологии развивались на протяжении десятилетий, мы использовали биты (двоичные цифры) вместо альтернатив, таких как тройные цифры.

Чтобы сделать большие числа, мы объединяем несколько битов. Таким образом, два бита могут вместе иметь четыре значения. Три бита могут иметь восемь значений и так далее. В старых компьютерах иногда биты были группой шесть или десять одновременно. Тем не менее, восемь стали обычным делом, и теперь это по сути стандарт. Использование восьми битов для байта не имеет такой сильной физической причины, как некоторые другие группы, которые я описываю, но это путь мира.

Еще одна особенность компьютеров - память. Когда у нас есть эти байты, мы хотим сохранить их много в устройстве, которое легко доступно для процессора, чтобы мы могли быстро получить много байтов в процессор и из него. Когда у нас много байтов, нам нужен способ, чтобы процессор мог указать памяти, какие байты процессор хочет прочитать или записать. Таким образом, процессору нужен способ адресации байтов.

Процессор использует биты для значений, поэтому он собирается использовать биты для значений адресов. Таким образом, память будет построена так, чтобы принимать биты, чтобы указать, какие байты должны быть предоставлены процессору, когда процессор читает, или какие байты должны быть сохранены, когда процессор пишет. Что делает запоминающее устройство с этими битами? Легко использовать один бит для управления одним переключателем путей к памяти. Память будет состоять из множества мелких частей, в которых хранятся байты.

Рассмотрим вещь в устройстве памяти, которая может хранить байт, и рассмотрим две из этих вещей рядом друг с другом, скажем, A и B. Мы можем использовать переключатель, чтобы выбрать, хотим ли мы, чтобы байт A был активным, или байт B, чтобы быть активным. Теперь рассмотрим четыре из этих вещей, скажем, A, B, C и D. Мы можем использовать один переключатель, чтобы выбрать, использовать ли группу A-B или группу C-D. Затем другой переключатель выбирает A или B (если используется группа A-B) или C или D (если используется группа C-D).

Этот процесс продолжается: каждый бит в адресе памяти выбирает группу единиц хранения для использования. 1 бит выбирает между 2 единицами памяти, 2 выбирает между 4, 3 выбирает между 8, 4 выбирает между 16 и так далее. 8 битов выбирают из 256 единиц хранения, 24 бита выбирают из 16 777 216 единиц хранения, а 32 бита выбирают из 4 294 967 296 единиц хранения.

Есть еще одно осложнение. Перемещение отдельных байтов между процессором и памятью происходит медленно. Вместо этого современные компьютеры организуют память в большие части, такие как восемь байтов. Вы можете перемещать только восемь байтов за раз между памятью и процессором. Когда процессор запрашивает, чтобы память предоставила некоторые данные, процессор только отправляет старшие биты адреса - младшие три бита выбирают отдельные байты в пределах восьми байтов, и они не отправляются в память.

Это быстрее, потому что процессор получает восемь байтов за то время, которое потребовалось бы для того, чтобы память полностью переключилась на один байт, и дешевле, потому что вам не нужно огромное количество дополнительных переключателей, которые потребовались бы для различения отдельных байты в памяти.

Однако теперь это означает, что процессор не может получить отдельный байт из памяти. Когда вы выполняете инструкцию, которая обращается к отдельному байту, процессор должен прочитать восемь байтов из памяти, а затем сдвинуть эти байты внутри процессора, чтобы получить желаемый байт. Аналогично, чтобы получить два или четыре байта, процессор считывает восемь байтов и извлекает только те байты, которые вы хотите.

Чтобы упростить этот процесс, разработчики процессоров указывают, что данные должны быть выровнены определенным образом. Как правило, они требуют, чтобы двухбайтовые данные (например, 16-разрядные целые числа) были выровнены с кратными по два байта, четырехбайтовые данные (например, 32-разрядные целые числа и 32-разрядные значения с плавающей запятой) должны быть выровнены по кратным четырем байты и восьмибайтовые данные должны быть выровнены с кратными восьми байтов.

Это необходимое выравнивание имеет два эффекта. Во-первых, поскольку четырехбайтовые данные могут начинаться только в двух местах в восьмибайтовом чанке, считанном из памяти (начало или середина), разработчикам процессоров нужно только подключить провода, чтобы извлечь четыре байта из двух мест. Им не нужно добавлять все дополнительные провода, чтобы извлечь четыре байта из любого из восьми отдельных байтов, которые могут быть начальными местами, если какое-либо выравнивание было разрешено. (Некоторые процессоры полностью запрещают загрузку невыровненных данных, а некоторые процессоры позволяют это, но используют медленные методы для извлечения, которые используют меньше проводов, но используют итеративный алгоритм для смещения данных в течение нескольких циклов процессора, поэтому невыровненные загрузки медленные.)

Второй эффект заключается в том, что, поскольку четырехбайтовые данные могут начинаться только в двух местах в восьмибайтовом фрагменте, они также заканчиваются внутри этого фрагмента. Подумайте, что произойдет, если вы попытаетесь загрузить четыре байта данных, которые начинаются с шестого байта восьмибайтового фрагмента. Первые два байта находятся в чанке, но следующие два байта находятся в следующем чанте в памяти. Процессор должен будет прочитать два фрагмента из памяти, взять разные байты из каждого из них и объединить эти байты. Это намного медленнее, чем просто чтение одного куска.

Таким образом, память организована по степеням двух, потому что это естественный результат битов, а процессоры требуют выравнивания, потому что это делает доступ к памяти более эффективным. Выравнивание, естественно, является степенью двойки, и поэтому размеры вашей структуры работают лучше, когда они кратны степеням двух, которые используются для выравнивания.

Я не знаю о PDP-5, но некоторые более поздние PDP имели 6-битные байты. Таким образом, выравнивание по слову будет совпадением с кратным 2.
Это не означает строгого требования. На самом деле нет никакой причины для машины иметь степень двух битов на слово. Ранние машины иногда использовали 12 бит (например, PDP-5). Так что, если вы кодируете C для запуска на PDP-5, возможно, понадобятся структуры, выровненные по 3-байтам или двум 12-битным словам.
В добавление к вышесказанному: даже если бы память была организована в других единицах, таких как 6 байтов, было бы трудно обрабатывать выравнивание в кратных единицах этой единицы. Легко определить, кратен ли адрес степени двух: Проверьте, равны ли младшие биты нулю. Трудно определить, кратен ли адрес шести: Вы должны вычислить остаток. У процессоров есть арифметические единицы для этого, но низкоуровневые механизмы аппаратной адресации намного проще и не могут выполнять эту арифметику. Поэтому было бы дорого делать оборудование, которое находит подходящий блок памяти для групп из 6 человек.

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