Дополнительные байты при объявлении члена структуры как uint32_t
У меня проблема при использовании типа uint32_t из библиотеки stdint.h. Если я запускаю следующий код (в Ubuntu linux 11.10 x86_64, g++ версия 4.6.1):
#include "stdint.h"
#include <iostream>
using std::cout;
typedef struct{
// api identifier
uint8_t api_id;
uint8_t frame_id;
uint32_t dest_addr_64_h;
uint32_t dest_addr_64_l;
uint16_t dest_addr_16;
uint8_t broadcast_radius;
uint8_t options;
// packet fragmentation
uint16_t order_index;
uint16_t total_packets;
uint8_t rf_data[];
} xbee_tx_a;
typedef struct{
// api identifier
uint8_t api_id;
uint8_t frame_id;
uint16_t dest_addr_64_h;
uint16_t dest_addr_64_l;
uint16_t dest_addr_16;
uint8_t broadcast_radius;
uint8_t options;
// packet fragmentation
uint16_t order_index;
uint16_t total_packets;
uint8_t rf_data[];
} xbee_tx_b;
int main(int argc, char**argv){
xbee_tx_a a;
cout<<"size of xbee_tx_a "<<sizeof (xbee_tx_a)<<std::endl;
cout<<"size of xbee_tx_a.api_id "<<sizeof (a.api_id)<<std::endl;
cout<<"size of xbee_tx_a.frame_id "<<sizeof (a.frame_id)<<std::endl;
cout<<"size of xbee_tx_a.dest_addr_64_h "<<sizeof (a.dest_addr_64_h)<<std::endl;
cout<<"size of xbee_tx_a.dest_addr_64_l "<<sizeof (a.dest_addr_64_l)<<std::endl;
cout<<"size of xbee_tx_a.dest_addr_16 "<<sizeof (a.dest_addr_16)<<std::endl;
cout<<"size of xbee_tx_a.broadcast_radius "<<sizeof (a.broadcast_radius)<<std::endl;
cout<<"size of xbee_tx_a.options "<<sizeof (a.options)<<std::endl;
cout<<"size of xbee_tx_a.order_index "<<sizeof (a.order_index)<<std::endl;
cout<<"size of xbee_tx_a.total_packets "<<sizeof (a.total_packets)<<std::endl;
cout<<"size of xbee_tx_a.rf_data "<<sizeof (a.rf_data)<<std::endl;
cout<<"----------------------------------------------------------\n";
xbee_tx_b b;
cout<<"size of xbee_tx_b "<<sizeof (xbee_tx_b)<<std::endl;
cout<<"size of xbee_tx_b.api_id "<<sizeof (b.api_id)<<std::endl;
cout<<"size of xbee_tx_b.frame_id "<<sizeof (b.frame_id)<<std::endl;
cout<<"size of xbee_tx_b.dest_addr_64_h "<<sizeof (b.dest_addr_64_h)<<std::endl;
cout<<"size of xbee_tx_b.dest_addr_64_l "<<sizeof (b.dest_addr_64_l)<<std::endl;
cout<<"size of xbee_tx_b.dest_addr_16 "<<sizeof (b.dest_addr_16)<<std::endl;
cout<<"size of xbee_tx_b.broadcast_radius "<<sizeof (b.broadcast_radius)<<std::endl;
cout<<"size of xbee_tx_b.options "<<sizeof (b.options)<<std::endl;
cout<<"size of xbee_tx_b.order_index "<<sizeof (b.order_index)<<std::endl;
cout<<"size of xbee_tx_b.total_packets "<<sizeof (b.total_packets)<<std::endl;
cout<<"size of xbee_tx_b.rf_data "<<sizeof (b.rf_data)<<std::endl;
}
тогда я получаю следующий вывод:
size of xbee_tx_a 20
size of xbee_tx_a.api_id 1
size of xbee_tx_a.frame_id 1
size of xbee_tx_a.dest_addr_64_h 4
size of xbee_tx_a.dest_addr_64_l 4
size of xbee_tx_a.dest_addr_16 2
size of xbee_tx_a.broadcast_radius 1
size of xbee_tx_a.options 1
size of xbee_tx_a.order_index 2
size of xbee_tx_a.total_packets 2
size of xbee_tx_a.rf_data 0
----------------------------------------------------------
size of xbee_tx_b 14
size of xbee_tx_b.api_id 1
size of xbee_tx_b.frame_id 1
size of xbee_tx_b.dest_addr_64_h 2
size of xbee_tx_b.dest_addr_64_l 2
size of xbee_tx_b.dest_addr_16 2
size of xbee_tx_b.broadcast_radius 1
size of xbee_tx_b.options 1
size of xbee_tx_b.order_index 2
size of xbee_tx_b.total_packets 2
size of xbee_tx_b.rf_data 0
То, что я делаю, это распечатывает общий размер структуры и размер каждого члена структуры.
В случае xbee_tx_b размеры членов складываются в размер структуры (14)
В случае xbee_tx_a размеры элементов составляют до 18 байт... но размер структуры составляет 20 байт!
Единственная разница между xbee_tx_a и xbee_tx_b заключается в типе членов dest_addr_64_X. Это uint32_t в xbee_tx_a и uint16_t в xbee_tx_b. Почему размер структуры больше, чем сумма размеров ее членов, когда я использую uint32_t? Откуда берутся эти 2 дополнительных байта?
Спасибо!
4 ответа
Структуры дополняются целым числом, кратным 4 байтам1, так что они выровнены по словам. http://en.wikipedia.org/wiki/Data_structure_alignment
Смотрите также:
- Почему sizeof для структуры не равен сумме sizeof каждого члена?
- Структура набивки и упаковки
- Использование struct padding
1 Как Mooing Duck, это не всегда так:
Это не всегда кратно 4 байта, оно меняется (немного) в зависимости от членов. С другой стороны, в 99% случаев это кратно 4 байтам.
Это из-за выравнивания. На вашей платформе uint32_t должен быть выровнен на 4 байта. Чтобы достичь этого, dest_addr_64_h должен иметь два байта заполнения перед ним, потому что позиция сразу после двух членов uint8_t кратна 2, но не 4.
Вы можете использовать макрос offsetof(), чтобы выяснить, где именно члены расположены внутри структуры, чтобы убедиться, что это правда.
Вы можете либо попытаться заставить компилятор упаковать элементы вместе, либо вы можете переставить элементы так, чтобы заполнение не было необходимым.
Вы должны объявить компилятору, чтобы упаковать структуру
Я считаю, что это будет работать для GCC
struct test
{
unsigned char field1;
unsigned short field2;
unsigned long field3;
} __attribute__((__packed__));
В MS это было бы что-то, используя упакованную прагму
http://www.cplusplus.com/forum/general/14659/
#pragma pack(push, 1) // exact fit - no padding
struct MyStruct
{
char b;
int a;
int array[2];
};
#pragma pack(pop) //back to whatever the previous packing mode was
Типы данных имеют различные требования к выравниванию в зависимости от платформы. Дополнительные байты используются для выравнивания одного из членов вашей структуры с определенным размером и / или положением. Если вам нужен более точный контроль, вы можете указать это выравнивание с __attribute__
или же #pragma pack