关于c语言中的字节对齐padding问题

  最近的工作中,发现有一个很奇怪的问题,就是两个结构体,里面的字段的值完全是一样的,但是用memcpy就是不返回0。大致是下面的代码:

  typedef struct _A { word a; word b; word c; byte d; }A; A aa, bb; memset(&aa, 0, sizeof(aa)); aa.a = 1; aa.b = 2; aa.c = 3; aa.d = 4; bb.a = 1; bb.b = 2; bb.c = 3; bb.d = 4; A *cc = new A; cc->a = 1; cc->b = 2; cc->c = 3; cc->d = 4; if (0 != memcmp(&aa, &bb, sizeof(A))) cout << "aa != bb" << endl; else cout << "aa == bb" << endl; if (0 != memcmp(&bb, cc, sizeof(A))) cout << "bb != cc" << endl; else cout << "bb == cc" << endl;

输出是:aa != bb

            bb != cc

 

为什么设的值都是一样的,但是memcmp就是返回不一样呢。memcpy还算是一个比较常用的函数,特别是在c语言中比较一个有较多字段的结构体,很方便。但是问题往往也就发生在这样的地方。

这里先要看下结构体A,一共是7个字节(以32位平台为例子)。但是编译器会进行字节对齐,我用的是vc2008,我不确定默认字节对齐是什么,用sizeof(A)来查看的话会得到8,好了,也就是说最后一个字节是编译器padding上去的,那这个padding上去的值是多少呢?

可以用下面的代码来看padding的字节的值:

printf("0x%X/n", *(word*)&aa.d); printf("0x%X/n", *(word*)&bb.d); printf("0x%X/n", *(word*)&cc.d); 输出是:0x4 0xCC04 0xCD04

从bb的输出来看padding上去的不是0,而是0xCC。而aa在前面已经用memset设置为0了,所以padding的值也变成0了。

而cc上又变成了0xCD。bb是分配的在栈上的,而cc是通过malloc分配得到的分配在堆上的内存,看来内存方式分配的不同,还会导致padding不同(但是经过测试,发现相同的内存分配方法的话对于同一个结构体内存是一样的)。

 

再来看memcmp(&aa, &bb, sizeof(A));sizeof(A)=8,所以memcmp会去比较8个长度的字节。所以aa,bb,cc的最后第二个字节(或最后一个字节,取决于内存是小端还是大端的)不同,导致memcmp失败。

 

从这个例子中可以发现使用memcmp比较特别是结构体的时候还是要十分小心的,最好还是逐个比较字段来的安全,除非你已经比较熟悉编译器的行为。虽然是个小错误,但是却很难发现尤其当程序没有异常结果时,但是却想一颗定时炸弹一样随时会爆炸...

你可能感兴趣的:(c)