当前位置:编程学习 > C/C++ >>

C语言中的内存对齐

最近看了好多,也编了好多C语言的浩强哥书后的题,总觉的很不爽,真的真的好怀念linux驱动的代码,好怀念那下划线,那结构体,虽然自己还很菜。
同时看了一遍陈正冲老师的C语言深度剖析,收益很多,又把唐老师的视频复习了一部分,感觉收获更多。

这阶段一直想写一篇博客,其实有好多东西,先写一下C语言中的内存对齐吧。

 

大家都知道,在C语言中定义一个变量,char是占用一个字节的,int占用四个字节,float占用四个字节,double占用八个字节,short占用两个字节,long int占用四个字节,long long神马的是64位机器用的,暂时不讨论。

上面说基本的数据类型所占用的字节数,程序的测试咱们printf一下(由于是菜鸟,所以咱们就不玩F8,F9的问题了)。程序如下:

 

include<stdio.h>  
 
int main(void) 
{ 
    char a; 
    short b; 
    int c; 
    long int d; 
    double e; 
    float f; 
     
    printf ("%d,%d,%d,%d,%d,%d\n",sizeof (a),sizeof (b),sizeof (c),sizeof (d),sizeof (e),sizeof (f)); 
    return 1; 
} 

#include<stdio.h>

int main(void)
{
 char a;
 short b;
 int c;
 long int d;
 double e;
 float f;
 
 printf ("%d,%d,%d,%d,%d,%d\n",sizeof (a),sizeof (b),sizeof (c),sizeof (d),sizeof (e),sizeof (f));
 return 1;
}

好了,我们可以知道这些数据类型占用的字节空间了,那么现在提出一个问题。

 

struct student 
{ 
    short s; 
    long b; 
}stu; 

struct student
{
 short s;
 long b;
}stu;

当我们以4字节的方式编译的时候,请问printf("%d",sizeof(stu));

我一直都认为这个打印的值是6,因为很明显嘛,short是两个字节的,long是四个字节的,所以打印出来的大小就是6个字节嘛。那好,请在VC下编译测试一下吧。

结果出来的是8!!!

出乎意料了,这就是内存对齐。

内存对齐的意义在于:处理器是以规定的字节数进行读取字节数的,我们编译的是以4字节读取字节数,这就是问题的所在。而且,读取的块的大小必须是2的N次幂。

下面我们解释一下,上面那个结构体打印出来的大小是8的原因。

原因:short类型占用两个字节,四个字节是一块的情况下,那么当一个short类型占用两个字节以后还剩下两个字节,但是接下来我们要存储的是四个字节的long型,如果按照打印六的话,那么我们的处理的取值将会蒙圈,所以实际上编译器把这两个数据分配的空间是short占用两个字节后空出两个字节的位置,这样完成了一个四个字节的块,然后接下来的一个long型占用四个字节,这样完成了两个块,所以我们打印出来的是8 。空说估计一会自己都晕了,所以画个图:

 

\

同时还要说一下内存的对齐的规则:

①必须要按照编译器指定的字节数进行读取,同时还要考虑怎么样才可以使编译器读取数据最快捷。

②另外最后占用的字节数必须是整个结构体中字节数最大数据类型的整数倍。

还有一些其他规则,下面再进行介绍。

 

一个结构体的问题差不多了吧?那么再看一个:

 

include <stdio.h>  
 
struct student 
{ 
    short s; 
    long b; 
}stu1; 
 
struct teacher  
{ 
    char c;   
    struct student stu1; 
    double e; 
}stu2; 
 
int main() 
{ 
    printf("%d,%d\n",sizeof(stu1),sizeof(stu2)); 
} 

#include <stdio.h>

struct student
{
 short s;
 long b;
}stu1;

struct teacher
{
 char c; 
 struct student stu1;
 double e;
}stu2;

int main()
{
 printf("%d,%d\n",sizeof(stu1),sizeof(stu2));

}咱们还是打印,那么打印出来的是多少呢?

这里说个插曲,在VC中默认的是8位编译,这个时候打印出来的是8和24,在linux下的GCC编译,打印出来的是8和20 。一直认为VC是4位编译,所以走了一些弯路,后来使用宏条件判断才知道VC是4位编译。下面分别说一下这种结构体嵌套结构体的内存对齐。

上面说的是4位的,那么这里我们还说继续先说4位的。

打印20的原因:

先说一下第二个结构体的第一个成员char,占用的是一个字节。第一个结构体的第一个成员short占用两个字节,第二个成员占用四个字节。好了,暂停一下,我这个时候我就疑惑了,为什么char和short不在一个四字节的块中呢,这样编译器也可以按照四字节进行很快速的读取啊?但是这个时候应该考虑的是,第一个结构体已经被编译器分配好了一个完整的空间,所以这个short是不可以并到第一个结构体中的。回到主题,第一个char单独占用一个字节的四字节的块,第一个结构体占用连个四字节的块,double为8字节,占用两个四字节的块,最后占用的是五个四字节的块。所以打印20 。

上图:
\
 

下面说一下当按照8字节进行编译的时候打印出24的原因。(虽然是8字节进行编译的,但是读取的还是按照四个字节进行读取的,这样的话前面说的原则仍然成立。)

原因如下:第一个char占用了一个字节,但是按照8字节存储,按照4字节读取,所以char占用了8字节前面的4字节,后面的四个字节被short占用,这样也完成了处理器最快速度读取并且没有破坏第一个结构体的整体性。剩下的一个一个long占用了一个四字节,我的同学说这个八字节的块要空出来四个,因为不可以把后来的double拆开,但是我认为这么解释不是很合理,我也不清楚原因是什么,所以暂时搁置。

上图:

 

\

先说这么多吧,这里面还有一些小东西,太晚了,各位建军节快乐吧,我明天还要继续我苦逼的实训道路。

 

补充:软件开发 , C语言 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,