zoukankan      html  css  js  c++  java
  • 字节对齐2

    字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节指低字节数据存放在内存低地址处,高字节数据存放在内存的高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处。基于X86平台的PC机是小端字节序的,而有的嵌入式平台则是大端字节序的。因而对int、uint16、uint32等多于1字节类型的数据,在这些嵌入式平台上应该变换其存储顺序。通常我们认为,在网络中传输的字节的顺序即网络字节序为标准顺序,考虑到与协议的一致以及与同类其他平台产品的互通,在程序中发数据包时,将主机字节序转换为网络字节序,收数据包处将网络字节序转换为主机字节序。
        对于下面的结构体:

    1. struct test
    2. {
    3.     char x1;
    4.     short x2;
    5.     float x3;
    6.     char x4;
    7. };

        结构各成员空间分配情况是怎么样的?
        文章中解释:
        结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填充了空字节。结构的第三个成员x3和第四个成员x4恰好落在了其自然对界地址上,在它们前面不需要额外的填充字节。在test结构体中,成员x3要求4字节对齐,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了 3个空字节。整个结构所占据空间为12字节。
        同时,说明了更改C编译器的缺省字节对齐方式:在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
     · 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
        · 使用伪指令#pragma pack (),取消自定义字节对齐方式。
        另外,还有如下的一种方式:
        · __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
        · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
        以上的n = 1, 2, 4, 8, 16... 第一种方式较为常见。

        下面是CSDN上提出的问题(原文<<intel和微软和本公司同时出现的面试题>>:http://community.csdn.net/Expert/TopicView3.asp?id=3804035)

    1. #pragma pack(8)
    2. struct s1
    3. {
    4.     short a;
    5.     long b;
    6. };
    7. struct s2
    8. {
    9.     char c;
    10.     s1 d;
    11.     long long e;
    12. };
    13. #pragma pack()

        问:
        (1)sizeof(s2) = ?
        (2)s2的c后面空了几个字节接着是d?
        
        下面是redleaves给出解释:
        很详尽,很透彻,从论坛原文后头的对话可以看出redleaves对C/C++的标准理解很深刻,值得学习:

    1. #pragma pack(8)
    2. struct S1
    3. {
    4. char a;
    5. long b;
    6. };
    7. struct S2 {
    8. char c;
    9. struct S1 d;
    10. long long e;
    11. };
    12. #pragma pack()

        sizeof(s2)结果为24。
        成员对齐有一个重要的条件,即每个成员分别对齐,即每个成员按自己的方式对齐。
        也就是说上面虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐。其对齐的规则是:每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对
    齐参数(这里是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。
        s1中,成员a是1字节,默认按1字节对齐,指定对齐参数为8,这两个值中取1,a按1字节对齐;成员b是4个字节,默认是按4个字节对齐,这时就按4个字节对齐。所以sizeof(s1) = 8。
        s2中,c和s1中的a一样,按1字节对齐,而d是个结构,它是8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,s1的就是4。所以,成员d就是按4字节对齐,成员e是8个字节对齐,它是默认按8个字节对齐,和指定的一样,所以它对到8字节的边界。这时,已经使用了12个字节了,所以又添了4个字节的空,从第16个字节开始放置成员e。这是,长度为24,已经可以按8(成员e按8字节对齐)整除。这样,一共使用了24个字节。
        a b
        s1的内存布局:11**,1111,
        c s1.a s1.b d
        s2的内存布局:1***,11**,1111,****11111111

        这里有三点很重要:
        (1)每个成员分别按自己的方式对齐,并能最小化长度;
        (2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度;
        (3)对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐;

        对于数组,比如:
        char a[3];这种,它的对齐方式和分别写3个char是一样的.也就是说它还是按1个字节对齐。
        如果写:typedef char Array3[3];
        Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度。
        不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个。

        下面是从另外一篇文章(http://community.csdn.net/Expert/TopicView3.asp?id=3564500)的一些对各个类型以及结构体对齐方式的补充:
        为了能使CPU对变量进行高效快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐“。例如对于4字节的int类型变量,其起始地址应该位于4字节边界上,即起始地址能够被4整除。变量的对齐规则如下(32位系统):
        Type
        Alignment
        char
        在字节边界上对齐
        short (16-bit)
        在双字节边界上对齐
        int and long (32-bit)
        在4字节边界上对齐
        float
        在4字节边界上对齐
        double
        在8字节边界上对齐
        structures
        单独考虑结构体的每个成员,它们在不同的字节边界上对齐。
        其中最大的字节边界数就是该结构的字节边界数。
        
        如果结构体中有结构体,那么这是一个递归的过程。   
        设编译器设定的最大对齐字节边界数为n,对于结构体中的某一成员item,它相对于结构首地址的实际字节对齐数目x应该满足以下规则:
        x = min(n, sizeof(item)
        例如,对于结构体:

    1. struct 
    2. {
    3.    char a; 
    4.    long b;
    5. }T;

        当位于32位系统,n = 8时:
        a的偏移量为0,b的偏移量为4,中间填充了3个字节,b的x为4。

        当位于32位系统,n = 2时:
        a的偏移量为0,b的偏移为2,中间填充了1个字节,b的x为2。

        结构体的sizeof:
        设结构体的最后一个成员为LastItem,其相对于结构体首地址的偏移为offset(LastItem),其大小为sizeof(LastItem),结构体的字节对齐数为N,则:结构体的sizeof 为: 若offset(LastItem)+ sizeof(LastItem)能够被N整除,那么就是offset(LastItem)+ sizeof(LastItem),否则,在后面填充,直到能够被N整除。
        另外:
        1) 对于空结构体,sizeof == 1;因为必须保证结构体的每一个实例在内存中都有独一无二的地址.
        2)结构体的静态成员不对结构体的大小产生影响,因为静态变量的存储位置与结构体的实例地址无关。例如:
        struct {static int I;} T;
        struct {char a; static int I;} T1;
        sizeof(T) == 1; sizeof(T1) == 1;




        引用:blog.csdn.net/xuegao007/article/details/1708360

  • 相关阅读:
    Problem D: 双向冒泡排序
    Problem C: 查找最大元素
    Problem D: 小平查密码
    Problem C: 文件单词首字母大写
    Problem B: 文件操作文本文件读入
    Problem A: 文件操作二进制文件读入
    Problem A: 实现链表(线性表)
    【leetcode】包含min函数的栈
    【leetcode】反转链表
    【leetcode】合并两个排序的链表
  • 原文地址:https://www.cnblogs.com/zjoch/p/6002568.html
Copyright © 2011-2022 走看看