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不行吗?

解决方案 »

  1.   

    我分别对你的两个问题进行回答,可能不是很确切。
    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位对齐方式,效率都是一样的
      

  2.   

    1 这个是利用union的内存特性判断当前cpu类型的,到底是大头还是小头,  
      小头的话01 00 00 00,那么endian就等于1,
      大头的话00 00 00 01,那么endian等于0 
      

  3.   

    首先,Little Endian和Big Endian与字节对齐没有关系,一般的,X86机器上面用的都是LittleEndian的编码方式,Power PC上面用的是BigEndian编码方式。网络传输过程中使用的都是Big Endian编码方式,所以在做网络通信的时候需要考虑到这方面的问题,还有就是嵌入式的跨平台程序,也需要考虑这方面的问题,容易造成解码错误。
    其次,内存的对齐问题是跟本机的字长相关的,32位机的字长是4字节,所以默认的对齐长度是4,嵌入式的系统,比较常见的字长是2字节,所以默认的对齐长度是2;内存对齐可以在代码内部控制,一般的默认的对齐长度跟同结构的最长变量相等。
    不同的平台和编译器差异很大,一般的都是具体问题具体分析了,如果开发的是本机程序就不用考虑这方面的问题了
      

  4.   

    我觉得6楼对结构体的理解有误.
    这里有个帖子:
    http://dev.csdn.net/article/48/48195.shtm
      

  5.   

    很多人没有理解我的意思,
    他大可以直接定义 char endian=1;
    但是他没有,而是
    static union { int x; char endian; } little = { 1 }
    而x根本没用到,为什么?目前比较支持2楼的解释
      

  6.   


    因为用联合体可以使得内存共享。如果你直接定义 char endian=1; 那么endian永远为1,无论是big endian 还是 little endian。
    这样就不能判断到是big 还是 little endian了但如果你用uninon,就像10楼所说的那样,可以判断是big endian 还是 little endian了。
      

  7.   


    static union { int x; char endian; } little = { 1 };这里的1是赋值给x吗?
      

  8.   

    如果改成
    static union {char endian; int x;} little = { 1 };
    可以吗
      

  9.   

    10楼正确。
    这个联合的使用与对齐无关,也根本不是为了对齐才这样写。
    给它赋一个1以后,如果是小端,endian就是1,否则就是0。
    static union { short x; char endian; } little = { 1 }; 这样写也能达到作者的目的。
      

  10.   


    不可以,endian 总是1了。
      

  11.   


    可以吧,这个跟联合体里面的元素的位置无关的啊。1是int型,优先赋给x的。
      

  12.   

    不可以,我试过了,1是赋值给char的