今天的课是由同届的同学来讲的,真是讲得好精彩!
就我个人感觉来看,已经达到平均水准以上了。稍稍留意了一下,无论是习惯、用语、节奏,都是与我一直接触的老师们别无二样;
作为和他一届的同学真是倍感压力。
啊话题扯远了,临下课前老师借由#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 条评论
不错!
谢谢观看,看来最近这问题出现得挺频繁的
这一篇,其实我以前看过了,就是忘了==