关于struct的字节对齐

今天的课是由同届的同学来讲的,真是讲得好精彩!

就我个人感觉来看,已经达到平均水准以上了。稍稍留意了一下,无论是习惯、用语、节奏,都是与我一直接触的老师们别无二样;

作为和他一届的同学真是倍感压力。

啊话题扯远了,临下课前老师借由#pragma提到了struct字节对齐的内容,我也只是不久前刚了解的,真是堪堪赶上教学进度~于是写这篇日志总结顺便再温习一下。

给出这样一段代码:

struct test{
    char a;
    long b;
};
void main(){
    struct test t1,t2;
    memset(&t1,0,sizeof(struct test));
    t2.a=0;
    t2.b=0;
    if (memcmp(&t1,&t2,sizeof(struct test))==0){
        printf("yes\n");
    }else{
        printf("no\n");
    }
    printf("%d\n",(int)sizeof(struct test));
}
看到声明了两个同类结构体t1,t2,t1使用memset归零,t2则是将成员变量全部归零。在主流编译器上,其结果竟然是no!
最后打印出的struct大小也不是char+long的5字节,而是8字节。

 

究其原因,是因为编译器对struct进行了对齐处理。因而t2只归零了5字节,memcmp会返回不一致。
查看详情,char占据了第一个字节没问题,但是之后的3个字节都空着,直到第4个字节才开始放long。

 

为什么要进行对齐处理呢?
有些平台上变量不对齐会出错,而有些平台上变量对齐可以提升对内存的读写速度(比如说一个读周期读4个字节,连续读取下每次读都是从偶地址开始。如果long是放在2-5字节的话,就要读两次才行)
对struct对齐处理的规则有两条:
1.每个变量相对头部的偏移量必须是它大小的整数倍,例:char a;long b;  b就要从他体积的整数倍(4的倍数)处开始放,因而放完一个字节的char后,要再空3个字节才可以放b
2.所有变量都存放完毕后,整个struct的体积要能被其最大成员的体积整除
例:
struct s1{
    char a;
    long b;
};
struct s2{
    char a;
    struct s1 s;
    char b;
};
则s1的大小为8字节,其作为整体时对齐长度不再是体积,而是其内部最大成员即long的4字节
s2在地址对齐时,先分配给a一个字节,再空3个字节保证s的偏移量能被4整除,再放s(8个字节),再放一个字节的b
这时的大小为1+3+8+1=13,最后再补3个字节13+3=16,使得16能被最大成员s的对齐长度4整除。

 

可以看到,内存对齐是与具体变量的大小息息相关的。
有的变量大小在不同平台上有差异,这个时候可以使用#pragma pack(x)强制定义对齐字节的大小为x
一旦使用了#pragma pack(x),则每次计算地址对齐时,使用的不再是变量的大小,而是变量大小与x二者的最小值。
比如说先写了#pragma pack(2),则对于char类型还是按1字节对齐,而对于其他体积大于1字节的变量,都按照2字节对齐
可以使用#pragma pack()换回默认计算方式

 

目前的主流编译器都实现了对struct的内存对齐,但并不是所有编译器都支持(手头的老掉牙wintc就不支持,用这个来比赛真是太令人郁闷了)
另外寻求完美的代码高亮方案中,希望能不用插件、复制不会有行号

3 条评论

  1. zqf 说道:

    不错!

  2. Mickey 说道:

    这一篇,其实我以前看过了,就是忘了==

发表评论

电子邮件地址不会被公开。

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>