2013-12-09 5 views
5

Я работал с некоторыми (о чем я думал, что было) плохой код, который был союз, как:Союз выравнивания структуры данных

union my_msg_union 
{ 
    struct message5; 
    char buffer[256] 
} message; 

буфер был заполнен 256 байт из порта связи. Структура что-то вроде:

struct message5 { 
uint8 id; 
uint16 size; 
uint32 data; 
uint8 num_ids; 
uint16 ids[4]; 
} message5d 

же код был компилируется на кучах архитектур (8bit AVR, 16bit Филипс, 32-битный ARM, 32bit x86 и amd64).

Проблема, о которой я думал, заключается в использовании объединения: код всего лишь блока последовательных байтов в буфер, а затем считывает значения через структуру без учета выравнивания/заполнения структуры.

Разумеется, быстрый взгляд на sizeof (message5d) на разные системы дал разные результаты.

Что удивило меня, так это то, что всякий раз, когда существовал союз с char [], все экземпляры всех структур этого типа на всех системах отбрасывали их дополнение/выравнивание и делали их последовательными байтами.

Является ли это стандартом C или просто тем, что авторы компилятора внесли в «помощь»?

+1

Не только это не стандарт C, это не разрешено ... размер каждого экземпляра структуры message5 должны быть одинаковыми. –

+0

Можете ли вы продемонстрировать это с помощью короткой программы, которая выводит несогласованные размеры? –

+0

Нет никаких несогласованных размеров. Я имел в виду, что когда я скомпилирован без объединения, размер отличается от того, когда я компилирую с объединением. – Myforwik

ответ

3

Этот код демонстрирует противоположное поведение от одного вы описываете:

#include <stddef.h> 
#include <stdint.h> 
#include <stdio.h> 

struct message5 
{ 
    uint8_t id; 
    uint16_t size; 
    uint32_t data; 
    uint8_t num_ids; 
    uint16_t ids[4]; 
}; 

#if !defined(NO_UNION) 
union my_msg_union 
{ 
    struct message5 msg; 
    char buffer[256]; 
}; 
#endif /* NO_UNION */ 

struct data 
{ 
    char const *name; 
    size_t offset; 
}; 

int main(void) 
{ 
    struct data offsets[] = 
    { 
     { "message5.id", offsetof(struct message5, id) }, 
     { "message5.size", offsetof(struct message5, size) }, 
     { "message5.data", offsetof(struct message5, data) }, 
     { "message5.num_ids", offsetof(struct message5, num_ids) }, 
     { "message5.ids", offsetof(struct message5, ids) }, 
#if !defined(NO_UNION) 
     { "my_msg_union.msg.id", offsetof(union my_msg_union, msg.id) }, 
     { "my_msg_union.msg.size", offsetof(union my_msg_union, msg.size) }, 
     { "my_msg_union.msg.data", offsetof(union my_msg_union, msg.data) }, 
     { "my_msg_union.msg.num_ids", offsetof(union my_msg_union, msg.num_ids) }, 
     { "my_msg_union.msg.ids", offsetof(union my_msg_union, msg.ids) }, 
#endif /* NO_UNION */ 
    }; 
    enum { NUM_OFFSETS = sizeof(offsets)/sizeof(offsets[0]) }; 

    for (size_t i = 0; i < NUM_OFFSETS; i++) 
     printf("%-25s %3zu\n", offsets[i].name, offsets[i].offset); 
    return 0; 
} 

Образец продукции (GCC 4.8.2 на Mac OS X 10.9 Mavericks, 64-разрядная версия компиляции):

message5.id     0 
message5.size    2 
message5.data    4 
message5.num_ids    8 
message5.ids    10 
my_msg_union.msg.id   0 
my_msg_union.msg.size  2 
my_msg_union.msg.data  4 
my_msg_union.msg.num_ids  8 
my_msg_union.msg.ids  10 

Смещения в союзе такие же, как и смещения внутри структуры, как требует стандарт C.

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

Отметьте, что мне пришлось изменить uint8 и т.д. до uint8_t, но я не думаю, что это имеет значение. Если это так, вам нужно указать, какой заголовок вы получите, например, uint8.


Код обновлен для компиляции с union или без. Вывод при компиляции с -DNO_UNION:

message5.id     0 
message5.size    2 
message5.data    4 
message5.num_ids    8 
message5.ids    10 
+0

Вам нужны два источника - один с объединением и один без - для демонстрации того, что наблюдается (или нет). Конечно, в одной программе все экземпляры структуры будут иметь одинаковый макет. Но что наблюдается, если вы удалили союз из источника, который может (или может быть, не зависит от компилятора) быть другим. – slebetman

+2

@slebetman: Я не думаю, что согласен, но тривиально, чтобы код был скомпилирован без объединения, а вывод для структуры такой же, как и с объединением - конечно. –

+0

@slebetman Когда компилятор компилирует источник с/без объединения, он не может знать, будет ли он позже предоставлен другой источник без/с объединением, с двумя объектными файлами, связанными в одни и те же программы, - но он должен был знать чтобы иметь возможность компилировать структуру по-разному и соответствовать. Это не логически невозможно, но абсурдно и номологически невозможно. Таким образом, факт, как я уже сказал, заключается в том, что компилятор не может этого сделать. –

Смежные вопросы