当前位置:   article > 正文

浅谈sizeof_学而思编译器

学而思编译器

关于sizeof有一堆奇奇怪怪的问题,所以找了个时间将一些遇到的容易忘记的记录下来:

一、关于sizeof指针的问题:

        sizeof指针就是说  一个指针变量占用多少内存空间。那么指针是用来干什么的呢?是用来存储一个地址的。也就是说不管指针指向什么类型的变量,他的大小一定是固定的(因为只是用来放地址,和指向哪里指向谁无关)那么只需要知道存放一个地址需要几个字节就好了。因此答案很简单,就是一个int类型的大小;为4字节。

所以无论是int* char* 还是double* 的指针用sizeof得到的返回值都是4

二、关于sizeof空类和空结构体的问题:

        由于我一开始也不是很了解 所以先贴测试代码 如下:

  1. #include<iostream>
  2. using namespace std;
  3. typedef struct
  4. {
  5. }St_A;
  6. class Cl_A
  7. {
  8. };
  9. int main()
  10. {
  11. cout<<"sizeof nil struct :"<<sizeof(St_A)<<endl;//g++编译结果为1
  12. cout<<"sizeof nil class :"<<sizeof(Cl_A)<<endl;//g++编译结果为1
  13. return 0;
  14. }

那么为什么会是1呢?我也在百度上找了答案 目前看来应该是这样:

    一个类或者一个结构体 即使是空的,编译器也会预留空间给他们以便标记他们,同时要使他们所占用的空间最少,所以默认分配了1字节(应该和编译器也有一定关系吧?)

三、关于sizeof结构体的计算:

       由于字节对齐的关系导致计算结构体大小有点让人摸不清头脑。每种类型的数据所占的空间不同大家应该是知道的,所以计算机为了快速的读取数据,会将数据存放在一些特殊的位置用于提高计算机的读取速率。比如int类型占4个字节那么该类型的变量默认存储在地址能被4整除的起始位置。

字节对齐一般来说满足3个条件:

        1.结构体变量的首地址能够被其最宽基本类型成员的大小所整除;//这条有编译器去管理 我们只关注下面两条
        2.结构体每个成员相对于结构体首地址的偏移量都是当前成员大小的整数倍(如果当前成员是结构体,那么取结构体中最大的数据类型所占字节数),如有需要编译器会在成员之间加上填充字节;
        3.结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

        (基本类型是指内置数据类型 如int double char 等)

下面结合代码具体分析下

  1. #include<iostream>
  2. using namespace std;
  3. typedef struct
  4. {
  5. char a;
  6. int b;
  7. char c;
  8. }St_A;
  9. typedef struct
  10. {
  11. char a;
  12. St_A st1;
  13. char b;
  14. }St_B;
  15. int main()
  16. {
  17. cout<<"sizeof St_A:"<<sizeof(St_A)<<endl;
  18. cout<<"sizeof St_B:"<<sizeof(St_B)<<endl;
  19. return 0;
  20. }

对于结构体St_A其基本成员类型有char和int两种,最宽的是int占用4个字节,那么根据准则1,编译器会自动为结构体St_A分配一个能被4整除的首地址,St_A的第一个成员char的首地址就是结构体St_A的首地址,即偏移量为0,接下来,下一个成员变量int首地址如果不做处理的,应该是相对于St_A的偏移量是1,这就不满足条件2了,所以编译器开始在char的后面填充3个字节,使得int相对于St_A的偏移量是4,来满足条件2,然后结构体的大小就是1(char)+3(填充)+4(int)=8,然后下一个成员变量char相对于St_A的偏移量是8,满足条件2,这时B的总长度是1(char)+3(填充)+4(int)+1(char)=9,不满足条件3,继续填充3个字节,所以sizeof(St_A)=12。

 对于结构体St_B,其中包括了一个复合类型,查看基本类型的时候,要将其中的结构体St_A拆分成char和int两种类型来看,所以结构体St_B中的基本数据类型是char,char,int,char,最宽的数据类型是int,编译器会自动为St_B分配一个能被4整除的首地址,St_B的第一个成员char的首地址就是结构体St_B的首地址,即偏移量为0,接下来,下一个成员变量St_A的首地址,如果不做处理的话,应该是相对于St_B的偏移量是1,这就不满足条件2了,所以编译器开始在char的后面填充3个字节,使得成员St_A相对于所在结构体St_B的地址偏移量是4,来满足条件2,这时加上St_B的长度12,St_B中最后一个成员char相对于St_B来说地址偏移量是16,能满足条件2,所以不需要在St_A的后面填充字节,这时St_B的总长度是1(char)+3(填充)+12(A)+1(char)=17,不满足条件3,所以还需要在最后一个char后面再添加3个字节,最后得到St_B的总大小是1(char)+3(填充)+12(A)+1(char)+3(填充)=20,所以sizeof(St_B)=20。

更新:

    关于sizeof,他是一个单目运算符而不是一个函数,他的工作在编译期间就已经完成了,他不会运行在他内部的表达式

例如 int i= 1;sizeof(i++);printf("%d",i);以上在运行完毕之后得到的输出结果是1.





声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/234888
推荐阅读
相关标签
  

闽ICP备14008679号