Чтение двоичных данных в структуры памяти, странные эффекты - PullRequest
2 голосов
/ 04 июня 2010

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

uint8_t dataz[] = { 1, 2, 3, 4, 5, 6 };

struct mystruct {

    uint8_t dummy1[1];
    uint16_t very_important_data;
    uint8_t dummy2[3];

} *mystruct = (void *) dataz;

printf("%x\n", mystruct -> very_important_data);

Что вы ожидаете, должен быть выход? Я бы сказал, х302, но нет. Это дает мне х403. Так же, как при использовании этой структуры:

struct mystruct {

    uint8_t dummy1[2];
    uint16_t very_important_data;
    uint8_t dummy2[2];

} *mystruct = (void *) dataz;

Как бы вы это объяснили?

Ответы [ 4 ]

5 голосов
/ 04 июня 2010

Как уже упоминали другие, если ваше выравнивание компилятора не выровнено по байту, в вашей структуре, скорее всего, будут "дыры". Компилятор делает это, потому что ускоряет доступ к памяти.

Если вы используете gcc, есть атрибут «упакованный», который приведет к выравниванию структуры по байту и удалит «дыры»:

struct __attribute((__packed__)) mystruct {
    uint8_t dummy1[1];
    uint16_t very_important_data;
    uint8_t dummy2[3];
} *mystruct = (void *) dataz;

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

Отображение структур в двоичные данные обычно непереносимо, даже если вы прямо сейчас работаете на своем компьютере.

5 голосов
/ 04 июня 2010

Упаковка. Не гарантируется, как члены структуры физически расположены внутри структуры. Они могут быть выровнены по словам, оставляя пробелы.

В некоторых версиях C существуют прагмы для точного управления упаковкой.

3 голосов
/ 04 июня 2010

Скорее всего, компилятор добавил байты заполнения между dummy1 и very_important_data для выравнивания very_important_data по 16-битной границе.

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

2 голосов
/ 04 июня 2010

Это зависит от компилятора, но обычно компилятор выравнивает каждый элемент в соответствии с его естественным выравниванием. В случае, если вы столкнулись, very_important_data - это uint16_t, который, вероятно, имеет естественное выравнивание 2 байта.

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