对齐,请小心!

    对于习惯了上层开发的人们,在开发具有严格格式约束(如,网络底层应用)系统时,往往会忽略一个重要的问题——对齐,从而导致程序正确,但结果不正确的Bug。
    大多数情况下,我们总是非常信任编译器,相信她会给予我们所想象的二进制代码,诚然,在大部分情况下,她还是很听话的,但是偶尔也有不如尔意的时候。如果你是初次遇到这种问题,很可能会废掉你大半天的时间来怀疑是代码的问题。
    最近,在开发一个网络程序时就遭遇了这样一个问题。下面为其中一个功能对应的ARP数据包结构:
000001    typedef struct _DLCHeader
000002    {
000003        unsigned char m_receiverMAC[6];
000004        unsigned char m_senderMAC[6];
000005        unsigned short m_ethertype;
000006    }DLCHeader;
000007    typedef struct _ARPFrame
000008    {
000009        unsigned short m_hardwareType;
000010        unsigned short m_protocolType;
000011        unsigned char m_lengthMAC;
000012        unsigned char m_lengthIP;
000013        unsigned short m_opCode;
000014        unsigned char m_senderMAC[6];
000015        unsigned long m_senderIP;
000016        unsigned char m_receiverMAC[6];
000017        unsigned long m_receiverIP;
000018    }ARPFrame;
     如果严格地按照结构体所指定的字节数42,程序一点问题没有。但是,在默认情况下Visual Studio (.NET)是根据系统参数(总线宽度)来选择在编译过程中是否往数据结构中填充额外数据来满足要求,此过程称为对齐。虽然说这样优化性能,但是对于需要严格构造底层数据包,这种优化无疑给我们带来了麻烦。下面对比一下采用默认对齐和1Byte对齐的结果:
采用默认对齐,填充了10Byte
Packet length, captured portion: 62, 62
00000000 : 00 16 76 d2 53 e8 00 14 78 97 dc 86 08 00 45 00 ..v.S...x.....E.
00000010 : 00 30 00 00 40 00 36 06 9f fb 40 d7 a2 40 c0 a8 .0..@.6...@..@..
00000020 : 01 0d 00 50 06 3c a1 d6 bd b9 3b 8b 48 b5 70 12 ...P.<....;.H.p.
00000030 : 16 d0 dd 1d 00 00 02 04 05 ac 01 01 04 02       ..............

采用1Byte对齐,得到正确的数据包
Packet length, captured portion: 42, 42
00000000 : 00 16 76 d2 53 e8 01 02 03 04 05 06 08 06 00 01 ..v.S...........
00000010 : 08 00 06 04 00 01 01 02 03 04 05 06 c0 a8 01 01 ................
00000020 : 00 16 76 d2 53 e8 c0 a8 01 0d                   ..v.S.....
     Visual Studio提供了关于对齐的编译选项,在[代码产生(Code Generation)]的[结构成员对齐(Struct Member Alignment)]。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值