zoukankan      html  css  js  c++  java
  • C语言字节对齐

    什么是字节对齐?

    现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

    为什么要字节对齐?

    字节是否对齐关系到CPU访问数据时的效率问题,假设一个CPU每次总是从内存中取出4个字节,从内存编号为0的地方开始,现在我定义一个char a,定义一个int b,让他们按顺排列在内存中,就是这样的:

    char a占用1个字节,int a占用4个字节,CPU每次总是取4个字节,这时我想要取b时,需要先取出0-3,再取出4-7,然后将1-4拼在一起,这样就需要取两次,但是,如果我让char aint b按照特定的顺序排列:

    这样我只需要取一次就能将b取出,提升了CPU的工作效率。

    字节对齐的概念和规则

    概念:

    • 数据类型自身的对齐值:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float类型,其自身对齐值为4,对于double型,其自身对齐值为8(单位字节)。
    • 结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
    • 指定对齐值:#pragma pack (value)时的指定对齐值value。
    • 数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。

    规则:
    有效对齐值N是最终用来决定数据存放地址方式的值,最重要。
    有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0"。而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整。

    举例说明

    代码如下

    #include <stdio.h>
    
    struct Test
    {
    	char a;
    	int b;
    	short c;
    };
    int main(void)
    {
    	struct Test t = {'a',1,2};
    	printf("%d 
    ",sizeof(t));
    	getchar();
    	return 0;
    }
    

    如果我们不知道字节对齐规则,那么一定会认为这个结构体的大小是这样的,char类型1个字节,int类型4个字节,short类型2个字节一共7个字节,执行一下看看结果:

    执行之后的结果是12,我们先来看一下反汇编代码:

    根据反汇编代码我们可以看到a,b,c中的值分别存放在ebp-0ch,ebp-8,ebp-4这三个地方,我们到内存中看一下他们是怎么排列的:

    可以看到char占用1个字节,int占用4个字节,short占用2个字节,但是并没有我们想象的那样紧挨着排放,而是有一定的排放规则。这里就体现出了字节对齐,因为我这里是32位的机器,默认是4字节对齐,下面来详细的说一下是怎么排列的:
    假设基址为0012FF3C,从偏移地址为0的位置开始存放

    • 根据上面的字节对齐规则,a是char类型,自身对齐值就是1字节,b是int类型,自身对齐值是4字节,c是short类型,自身对齐值是2字节
    • 结构体的自身对齐值:结构体中自身对齐值最大的那个,根据上面的分析这个结构体的自身对齐值为4字节
    • 指定对齐值:因为我们没有指定对齐值,使用的是默认的4字节对齐
    • 数据成员有效对齐值:自身对齐值和指定对齐值中小的那个值,a的自身对齐值是1,指定对齐值是4,较小值是1,那么a的对齐值就是1;b的自身对齐值是4,指定对齐值是4,较小值是4,那么a的对齐值就是4;c的自身对齐值是12,指定对齐值是4,较小值是2,那么c的对齐值就是2,假设有一个变量是long类型,那么这个变量的对齐值应该为4.

    这样,a占用1个字节,存放在偏移地址为0的内存,0%1=0,没有问题。

    b占用4个字节,如果将他挨着变量a存放,也就是存放在偏移地址为1的位置,1%4=1,这样就存在问题了,所以b存放到偏移地址为4的位置,4%4=0。

    最后,c占用2个字节,如果将他挨着b存放,也就是存放到偏移地址为8的位置,8%2=0,没有问题,所以c存放到 偏移地址为8的位置,占两个字节。

    这样就排列好了,这时,发现a,b,c一共才占用了10个字节,因为结构体还没有根据自身有效对齐值圆整,根据上面的分析,这个结构体的自身对齐值是4,12%4=0,所以结构体会再占用两个字节,10和11,也就是A和B,这样就得出这个结构体的实际大小是12。

    当然,除了使用默认的对齐值,我们还可以自己使用#pragma pack (value)指定对齐值:

    #include <stdio.h>
    #pragma pack (2)
    
    struct Test
    {
    	char a;
    	int b;
    	short c;
    };
    int main(void)
    {
    	struct Test t = {'a',1,2};
    	printf("%d 
    ",sizeof(t));
    	getchar();
    	return 0;
    }
    

    这将对齐值设置成2,那么a,b,c在内存中的排列方式应该是这样的:

    要注意,这里的int b的自身对齐值是4字节,有效对齐值是2字节。

  • 相关阅读:
    Spring Cloud Hystrix Dashboard的使用 5.1.3
    Spring Cloud Hystrix 服务容错保护 5.1
    Spring Cloud Ribbon 客户端负载均衡 4.3
    Spring Cloud 如何实现服务间的调用 4.2.3
    hadoop3.1集成yarn ha
    hadoop3.1 hdfs的api使用
    hadoop3.1 ha高可用部署
    hadoop3.1 分布式集群部署
    hadoop3.1伪分布式部署
    KVM(八)使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机
  • 原文地址:https://www.cnblogs.com/Timesi/p/12248059.html
Copyright © 2011-2022 走看看