«Смещение» элемента конструкции может произойти только в том случае, если требования к выравниванию элемента конструкции намеренно скрыты. (Или если для подавления выравнивания используется какой-то специфичный для реализации механизм, например атрибут packed
в gcc.)
Например, в упомянутой проблеме проблема в том, что есть структура:
struct {
// ... stuff
int val;
unsigned char data[DATA_SIZE];
// ... more stuff
}
и программист пытается использовать data
, как если бы это было size_t
:
*(size_t*)s->data
Однако программист объявил data
как unsigned char
, и поэтому компилятор только гарантирует, что он выровнен для использования в качестве unsigned char
.
Так получилось, что data
следует за int
и поэтому также выровнено по int
. На некоторых архитектурах это будет работать, но на целевой архитектуре size_t
больше, чем int
и требует более строгого выравнивания.
Очевидно, что компилятор не может знать, что вы собираетесь использовать член структуры, как если бы это был какой-то другой тип. Если вы сделаете это и скомпилируете для архитектуры, требующей надлежащего выравнивания, вы, вероятно, столкнетесь с проблемами.
Упомянутый поток предлагает вставить битовое поле нулевой длины size_t
перед объявлением массива unsigned char
, чтобы принудительно выровнять массив для size_t
. Хотя это решение может работать на целевой архитектуре, оно не является переносимым и не должно использоваться в переносимом коде. Нет никакой гарантии, что битовое поле нулевой длины будет занимать 0 бит, а также нет никакой гарантии, что битовое поле, основанное на size_t
, действительно будет сохранено в size_t
или будет соответствующим образом выровнено для любого использования, не связанного с битовым полем.
Лучшим решением было бы использовать анонимный союз:
// ...
int val;
union {
size_t dummy;
unsigned char data[DATA_SIZE];
};
// ...
С C11 вы можете явно указать минимальное выравнивание:
// ...
int val;
_Alignas(size_t) unsigned char data[DATA_SIZE];
// ...
В этом случае, если вы #include <stdalign.h>
, вы можете написать _Alignas
таким образом, который будет работать и с C++11:
int val;
alignas(size_t) unsigned char data[DATA_SIZE];
person
rici
schedule
14.05.2014