1.最近在看lcc源代码.有些内存对齐的不太明白,static union { int x; char endian; } little = { 1 };这里endian是字节序,就是"小序在前"或"大序在前"的意思,而联合体里面还定义了一个x
但是x都没用到,我猜定义x是为了内存对齐,让char endian在内存中的地址是4的整数倍,我知道
有些数如果不对齐的话可能要取2次才能从内存中取到寄存器,比如int类型的数,但是char类型是一个字节
的,无论对不对齐好像都只需要取一次,这里为什么要这样?2.我看到源代码中在申请内存的时候比如用malloc,他申请的内存都是4K或者10k之类的,请问这样申请会
比较高效吗,如果是3k或9k不行吗?
但是x都没用到,我猜定义x是为了内存对齐,让char endian在内存中的地址是4的整数倍,我知道
有些数如果不对齐的话可能要取2次才能从内存中取到寄存器,比如int类型的数,但是char类型是一个字节
的,无论对不对齐好像都只需要取一次,这里为什么要这样?2.我看到源代码中在申请内存的时候比如用malloc,他申请的内存都是4K或者10k之类的,请问这样申请会
比较高效吗,如果是3k或9k不行吗?
1、先跟你说一下大小端格式吧:大端格式和小端格式和对齐关系不大。大小端格式主要是用于区别网络上(线路上)的数据和存储在内存上的数据不一致的问题,并且对于一个字节是不区分大小端格式(在网络协议编程和USB协议编程中深有体会)。而对于WORD(字)和DWORD(双字)就有区别,一般的编译器如VC都是把高位放高地址,低位放低地址,也就是所谓的大端格式。然而在传输线上时,却是把高位放低地址,低位放高地址,也就是小端格式,你可以用网络监听工具自己抓包,看看数据包你就能明白了,或者用BusHound去抓USB的数据包,也能看到。
那么再说一下对齐方式。对于编译器,在X86或IA32(英特尔32位架构)下寻址范围是0-2的32次方了。并且由于总线是32位的,那么它默认就是32位对其。但是编译器不是这么做,为了优化这一点,编译器做了处理。尤其是你在定义结构体时,深有体会,因为结构体中的类型不一致,那么他会拿最大变量的字节数来对齐。举例如下:
typedef struct mystruct
{
char a;//1Byte
short b;//2Byte
int c;//4Byte
bool d;//1Byte
long e;//4Byte
}MYSTRUCT;
void main()
{
MYSTRUCT ms;
printf("a的地址:%d\nb的地址:%d\nc的地址:%d\nd的地址:%d\ne的地址:%d\n",&ms.a,&ms.b,&ms.c,&ms.d,&ms.e);
}
你用VC调试一下就会发现,编译器很神奇,我给你看一下结果,这个是在我机器上调试的:
a的地址:1245040
b的地址:1245042
c的地址:1245044
d的地址:1245048
e的地址:1245052
从上面你就能看到,本来a是一个字节的,但是编译器为了能够以最大字节(4字节)对齐,他就会让他分配4字节空间,你可能会说我说错了,因为程序就给他分了2字节,但是你再往下看,在它下面是2字节的,而编译器又有规定,为了避免浪费内存,他可以和其他不足4字节的变量合用一个4字节单元,而刚好他的一下一个变量是2字节的,那么刚好够4字节,满足4字节对齐。如果你把b变量换成4字节的话,那么a变量就会一人独自占有4字节单元。其他你可以自己看看,我就不解释了。所以当你看TCP/IP协议栈或者其他的协议时,你会发现一个很有趣的事情,设计协议栈的人为了考虑这个事情,特意把协议都做成4字节对齐,也就是不足4字节都会以保留位形式出现,就是这个道理。
2、用malloc申请内存是从栈上申请,根据自己栈内资源给用户一个大内存,以避免用户不够用而继续申请,在C++的Cstring类就是这么做的,系统一次会给他256字节,然后不够继续申请大的,他会把之前的释放掉。这个和效率是有关系的,但是只要满足32位对齐方式,效率都是一样的
小头的话01 00 00 00,那么endian就等于1,
大头的话00 00 00 01,那么endian等于0
其次,内存的对齐问题是跟本机的字长相关的,32位机的字长是4字节,所以默认的对齐长度是4,嵌入式的系统,比较常见的字长是2字节,所以默认的对齐长度是2;内存对齐可以在代码内部控制,一般的默认的对齐长度跟同结构的最长变量相等。
不同的平台和编译器差异很大,一般的都是具体问题具体分析了,如果开发的是本机程序就不用考虑这方面的问题了
这里有个帖子:
http://dev.csdn.net/article/48/48195.shtm
他大可以直接定义 char endian=1;
但是他没有,而是
static union { int x; char endian; } little = { 1 }
而x根本没用到,为什么?目前比较支持2楼的解释
因为用联合体可以使得内存共享。如果你直接定义 char endian=1; 那么endian永远为1,无论是big endian 还是 little endian。
这样就不能判断到是big 还是 little endian了但如果你用uninon,就像10楼所说的那样,可以判断是big endian 还是 little endian了。
static union { int x; char endian; } little = { 1 };这里的1是赋值给x吗?
static union {char endian; int x;} little = { 1 };
可以吗
这个联合的使用与对齐无关,也根本不是为了对齐才这样写。
给它赋一个1以后,如果是小端,endian就是1,否则就是0。
static union { short x; char endian; } little = { 1 }; 这样写也能达到作者的目的。
不可以,endian 总是1了。
可以吧,这个跟联合体里面的元素的位置无关的啊。1是int型,优先赋给x的。