关于c ++:将结构成员声明为uint32_t时的额外字节数

Extra bytes when declaring a member of a struct as uint32_t

我在使用stdint.h库中的uint32_t类型时遇到问题。如果我运行以下代码(在Ubuntu Linux 11.10 x86_64,G++版本4.6.1上):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#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<<"----------------------------------------------------------
"
;

   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;
}

然后我得到以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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成员的类型。它们是xbee-tx-a中的uint32,xbee-tx-b中的uint16。为什么使用uint32-t时结构的大小大于其成员大小的总和?这两个额外的字节来自哪里?

谢谢!


结构被填充为4字节1的整数倍,以便它们与字对齐。http://en.wikipedia.org/wiki/data_-structure_-alignment_data_-structure_-padding

参见:

  • 为什么结构的sizeof不等于每个成员的sizeof之和?
  • 结构填料和填料
  • 结构填充的使用

1正如@moing duck评论的那样,这并不总是正确的:

It's not always a multiple of 4 bytes, it varies (slightly) depending on the members. On the other hand, 99% of the time it's a multiple of 4 bytes.


这是因为对齐。在您的平台上,uint32_t需要4字节对齐。为了实现这个目的,dest_addr_64_h前面必须有两个字节的填充,因为两个uint8_t成员后面的位置是2的倍数,而不是4。

您可以使用宏OffStof()来精确地确定成员放置在结构中的位置,以查看这是真的。

你可以试着让编译器把成员打包在一起,或者你可以重新安排成员,这样就不需要填充了。


需要向编译器声明以打包结构

我相信这对海湾合作委员会有效

1
2
3
4
5
6
struct test
    {
            unsigned char  field1;
            unsigned short field2;
            unsigned long  field3;
    } __attribute__((__packed__));

在MS中,使用pragma packed

http://www.cplusplus.com/forum/general/14659/

1
2
3
4
5
6
7
8
#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的对齐方式。