2009-11-05 4 views
0

Итак, я кодирую некоторые структуры пакетов (Ethernet, IP и т. Д.) И заметил, что за некоторыми из них следует атрибут ((упакованный)), который мешает компилятору gcc пытаться добавить к ним дополнение , Это имеет смысл, потому что эти структуры должны идти на провод.Согласование Datastructure

Но тогда, я насчитал слова:

struct ether_header 
{ 
    u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ 
    u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ 
    u_int16_t ether_type;    /* packet type ID field */ 
} __attribute__ ((packed)); 

Это скопировано с сайта, но мой код также использует 2 uint8_t и 1 uint16_t. Это добавляет до двух слов (4 байта).

В зависимости от источника система предпочитает, чтобы структуры были выровнены по краям 4,8 или даже 16 бит. Итак, я не понимаю, почему нужен атрибут ((упакованный)), поскольку afaik не должен упаковываться.

Кроме того, почему двойные скобки ((упакованные)) почему бы не использовать одну пару?

ответ

5

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

Я считаю, что двойные скобки необходимы, чтобы сделать ваш код совместимым с не-gcc-компиляторами. Используя их, вы можете просто сделать это:

#define __attribute__(x) 

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

+0

Я забыл, что uint8_t были массивами; глупый, но хороший призыв к планированию перемен. – mamidon

2

Хотя ваша система может предпочесть некоторое определенное выравнивание, другие системы могут не работать. Даже если __attribute__((packed)) не имеет эффекта, это хороший штрих паранойи.

Что касается того, почему это двойная скобка, для этого расширения, специфичного для GCC, требуется двойная скобка. Одиночная скобка приведет к ошибке.

+0

Отличная точка. Рассмотрим 64-битную или будущую 128-битную систему. –

0

packed относится к набивке/выравниванию внутри структура, а не выравнивание структуры. Например

struct { 
    char x; 
    int y; 
} 

Большинство компиляторов выделит у со смещением 4, если не объявить, как-структуру упакованную (в этом случае у будет получить выделяется при смещении 1).

+1

использование упакованных на такой структуре очень плохой идеи, так как доступ к y будет задерживаться на нескольких платформах. –

+1

В более общем плане, в зависимости от структуры C для представления независимого от платформы формата данных, возникает проблема. упакованный просто торгует одной проблемой для другой. –

1
 
in win32, you can do like this: 
#pragma pack(push) //save current status 
#pragma pack(4)//set following as 4 aligned 
struct test 
{ 
char m1; 
double m4; 
int m3; 
}; 
#pragma pack(pop) //restore 
+0

Эти прагмы работают и в GCC. –

0

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

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