Дилемма выравнивания очень простой структуры c / c ++ - PullRequest
0 голосов
/ 13 июля 2020

Учитывая, что я правильно понимаю выравнивание, и учитывая, что у нас есть следующая структура:

struct someStruct{
    short i1;
    short i2;
    short i3;
};

Предполагается, что short - это 16-битное целое с 2-байтовым выравниванием и что мы используем 32-битную машину с x86 . Я так понимаю, размер этой структуры будет 6 байт. Однако я не понимаю, что происходит, если структура начинается с нечетного адреса памяти. Добавляет ли он отступ к структуре, чтобы вместо этого она «начиналась» с четной? Скажем, у нас есть массив этих структур. Будет ли это дополнительное заполнение только у первого элемента? Кроме того, имеет ли значение, является ли начальный адрес четным, но он начинается на полпути через СЛОВО процессора (т.е. наименьший читаемый блок памяти) или в начале его? Добавляется ли дополнение в любом из двух последних обстоятельств? Опять же, это заполнение добавляется только к первому элементу массива этих структур? Означают ли ответы на какой-либо из моих вопросов, что размер структуры является переменным в зависимости от того, где в памяти она создана? Означает ли это, что некоторые элементы структурных массивов однородного типа будут иметь размер в байтах, отличный от других?

Я также спрашиваю, есть ли какие-либо отличия, указанные c от этого topi c между c и c ++ . И если бы мне можно было напомнить, можно ли обходить массив структур с помощью арифметики указателя c так же, как с массивами примитивных типов.

ДЛЯ УТОЧНЕНИЯ И ОБНОВЛЕНИЯ:

Как на данный момент я знаю, что структура не может быть сохранена, начиная с нечетного адреса, но мне все еще интересно, есть ли какая-либо разница, если адрес, где хранится структура, начинается на полпути через СЛОВО ( т.е. наименьший читаемый блок памяти ) или вначале. Любая разница в том, как это объединяется / сохраняется / дополняется / вписывается в массивы / другие структуры данных и т. Д. структура данных, такая как эта, начинается с адреса памяти на полпути через СЛОВО памяти ( т.е. наименьший читаемый блок памяти ) в массиве или не в массиве?

ИЛЛЮСТРАЦИЯ (ЭТО ЕЩЕ ОДНО НЕДАВНИЕ ОБНОВЛЕНИЕ ПОЖАЛУЙСТА, СМОТРИ):

enter image description here enter image description here

after reading some answers, I screenshot wikipedia to show my source of confusion: введите описание изображения здесь

Ответы [ 3 ]

4 голосов
/ 13 июля 2020

Сама структура имеет выравнивание 2, поэтому она просто не может быть соответствующим образом создана по нечетным адресам.

2 голосов
/ 14 июля 2020

Предполагается, что short - это 16-битное целое число с 2-байтовым выравниванием и что мы используем 32-битную машину с x86. Я понимаю, что размер этой структуры будет 6 байтов.

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

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

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

* 1015 адрес памяти.

Если тип структуры имеет требование выравнивания как минимум два, то не будет начинаться с нечетного адреса, если вы каким-то образом не заставите его каким-либо образом обмана указателя. Если вы сделаете так принудительно смещение, то поведение доступа к структуре через смещенный указатель будет неопределенным. На практике среди наиболее вероятных вариантов поведения в целом следующие: (i) он просто работает, (ii) он работает, но доступ замедляется, и (iii) доступ вызывает сигнал времени выполнения.

Добавляет ли он отступ к структуре, чтобы вместо этого она «начиналась» с четной?

Заполнение - это характеристика c типа не экземпляров, а первый байт типа никогда не является байтом заполнения. Скорее, если вы позволите реализации выделить объект, она правильно выровняет выделение для типа. То же самое применимо и в C ++, если вы используете обычный оператор new (не размещение new), и если вы выделяете память вручную с помощью malloc(), то начало выделенного пространства гарантированно будет правильно выровнено для любого типа. Это может означать, что перед экземпляром есть пробел, который не приписывается какому-либо объекту, но не является «заполнением» в общепринятом смысле этого слова.

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

Более того, имеет ли значение, четный ли начальный адрес, но он начинается на полпути через СЛОВО процессора (т.е. наименьший читаемый блок памяти) или в его начале?

Не должно ' t имеет значение для вас . Если это имеет значение для оборудования или самой реализации C (C ++), тогда реализация должна принять это во внимание должным образом.

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

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

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

Я также спрашиваю, есть ли какие-либо отличия, указанные c от этого topi c между c и c ++ .

C ++ имеет более богатую систему типов, чем C, но конгруэнтные части имеют по существу те же правила.

возможно ли, что данные структура, подобная этой, начинается в адресе памяти на полпути через СЛОВО памяти (т.е. наименьший читаемый блок памяти) в массиве или не в массиве?

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

1 голос
/ 14 июля 2020

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

Ничто в C ++ не заботится о СЛОВАХ, поэтому это не имеет значения. структуры и примитивы могут быть в начале слова, в середине, в конце или охватывать несколько слов. Они никак не влияют друг на друга. Все, что имеет значение, это то, что компилятор автоматически установит его с правильным выравниванием для вас.

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

structs:       [i1  ][i2  ][i3  ][i1  ][i2  ][i3  ]
words:   [          ][          ][          ][          ]
bytes:   [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]

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

Я не знаю каких-либо различий между C и C ++ в этой области.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...