精华内容
下载资源
问答
  • 首先,在开始计算结构体占用字节大小之前,我们要先搞懂什么是结构体的对齐和补齐。为什么会有结构体的对齐与补齐。 CPU的数据传输方式: CPU的数据传输方式是一次传输2个(32位)或者8个(64位)字节的方式进行传输...

    在学习C语言的时候很多人可能遇到了和我同样的问题,就是无法正确计算出C语言结构体所占字节的总的大小。首先,在开始计算结构体占用字节大小之前,我们要先搞懂什么是结构体的对齐和补齐。为什么会有结构体的对齐与补齐。

    CPU的数据传输方式:

    CPU的数据传输方式是一次传输2个(32位)或者8个(64位)字节的方式进行传输(根据总线条数来确定),这里我们以64位系统来举例,如果你声明一个变量占用8个字节,且该变量的起始地址是1,由于CPU一次读取8个字节,读取字节的地址是从0到8,那么CPU要得到该变量的值,需要读取两次,降低了CPU的性能。为了提高CPU读取的性能和效率,采取了补齐的方法来优化CPU的执行效率。也就是说,你声明的8个字节的变量,一定会被CPU一次性读取,即改变量的初始地址,一定是从0开始,如果上一个变量不满足8字节,会自动被补齐来保证下一个字节的其实地址为CPU读取的初始地址。

    补齐和对齐:

    为了保证cpu每次在读取一个变量的时候都是从初始地址开始的,所以,将不满足8字节大小的变量进行补全。

    下面我们来看几个例子:

    struct A
    {
    	char a;
    	double b;
    	int c;
    };
    
    struct B
    {
    	double b;
    	char a;
    	int c;
    };
    
    struct C
    {
    	int c;
    	char a;
    	double b;
    };
    
    struct D
    {
    	char a;
    	int c;
    	double b;
    };
    

    结构体A内存分配:
    对char a分配一个字节,但是由于要与double补齐,所以,需要给char a添加7个补位,保证与double补齐。当系统给 int分配内存的时候,需要给double补齐,所以,也分配了8个字符,但是int实际占用4个字节,剩余都是补位。所以总共有24个字节。

    结构体B内存分配:
    double b分配8个字节,为了补齐int也分配8个字节,由于int实际占用4个字节,剩余都是补位,且剩余的字节数可以装下char类型字节,所以,char就不需要分配内存,即总共16个字节。

    C和D也是一样道理,总共16个字节。

    再如:

    struct 
    {
    	int i;
    	char c;
    	float a;
    }
    

    为了与float补齐,需要4+4=8个字节。

    因此,计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体中最大基本类型的大小。

    展开全文
  • 前几天有个小朋友问了我一下,关于C语言结构体占用空间的问题。觉得以后会对小可爱有点帮助,就打算先写一下。 struct Test { int a; char b; int c; } test; 理论上,结构体中的各个成员在内存中应该是连续...
  • C语言结构体字节对齐

    2021-06-11 00:10:36
    默认字节对齐C语言结构体字节对齐是老生常谈的问题了,也是高频面试题,现在我们来深入研究这个问题,彻底弄懂到底是怎么回事,给你一个结构体定义和平台机器位数就能手动计算出结构体占用字节数,...

      默认字节对齐

    C语言结构体字节对齐是老生常谈的问题了,也是高频面试题,现在我们来深入研究这个问题,彻底弄懂到底是怎么回事,给你一个结构体定义和平台机器位数就能手动计算出结构体占用字节数,现在我们不使用宏#pragma pack,采用默认字节对齐方式。

    先抛出结论:

    • 在一个结构体中第一个成员变量放在偏移为0的位置,以后的变量都存储在该变量占用字节数整数倍的地址上。

    • 结构体总大小,必须是内部最大成员变量的整数倍,不足的补齐。

    好了,现在我们直接写个小程序验证并分析是否真是这样一回事。

    struct st{
        short a1;
        short a2;
        short a3;
    };
    
    struct st2{
        long a1;
        short a2;
    };
    

    这里我们定义了两个很简单的结构体,short占用2个字节,struct st我们一眼就知道大小了6个字节,但是struct st2呢?笔者电脑是64位,那么long占用8个字节,short占用2个字节。我们先来按照结论进行分析,在struct st2中成员变量a1在偏移0处存储且占用8个字节,成员变量a2占用2个字节,由于8是2的倍数,所以a2在偏移8的位置存储,又因为有结论2,我们根据结论2可以得出,struct st2必须占用8的倍数大小,所以struct st2总大小是16个字节,不足的后面补齐。现在我分别打印出struct st1和struct st2占用字节数大小和struct st2各个成员变量地址,观察是否和分析的一样。

    int main() {
        struct st2 st_val2;
    
        printf("sizeof(long) = %d\n", sizeof(long));
        printf("sizeof(struct st) = %d\n", sizeof(struct st));
        printf("sizeof(struct st2) = %d\n", sizeof(struct st2));
        printf("st_val2 addr = %p\n", &st_val2);
        printf("st_val2 a1 addr = %p\n", &st_val2.a1);
        printf("st_val2 a2 addr = %p\n", &st_val2.a2);
    
        return 0;
    }
    

    编译运行输出:

    sizeof(long) = 8
    sizeof(struct st) = 6
    sizeof(struct st2) = 16
    st_val2 addr = 0x7ffee107f3b8
    st_val2 a1 addr = 0x7ffee107f3b8
    st_val2 a2 addr = 0x7ffee107f3c0
    

    现在我们看一下输出结果,struct st如我们所愿占用6个字节大小,struct st2也按照我们分析的一样占用16个字节。我们在程序中定义了一个struct st2类型变量st_val2,从输出中可以看出变量st_val2的a1成员变量和st_val2变量地址一样,成员变量a2在偏移8处存储(0x c0 = 0xb8 8)。一切如我们所愿,看起来好像挺简单的,我们知道C语言有丰富的数据类型,下面我们再定义一个更复杂的结构体。

    struct st3{
        int a1;
        char a2;
        short a3;
        long a4;
        char a5;
    };
    

    这个结构体包含了大量数据类型成员变量,再复杂的结构体也能按照我们的结论分析到底占用了几个字节。

    在struct st3中int型成员变量a1占用4个字节,在偏移0处存储,char型成员变量a2占用2个字节那么应该放在2的倍数地址处存储,a1已经占用了4个字节,所以a2应该在偏移4的地址存储。
    short型成员变量a3占用2个字节,也应该放在2的倍数地址处存储,所以a3在偏移6的地址处存储,a2后面填充1个字节。

    long型成员变量a4占用8个字节,应该放在8的倍数地址上存储,前面我们已经知道a3在偏移6的地址处存储,且占用2个字节8 = 6 2,所以a4应该在偏移8的地址处存储。

    最后一个char型成员变量a5占用一个字节,那么a5在偏移16地址处存储。

    现在我们计算一下struct st3结构体占用空间大小,从a5偏移出计算16 1 = 17。在struct st3中最大成员变量占用8个字节,所以结构体总大小应该是8的倍数,最后结构体总大小是17 7 = 24,这里的7个字节在最后补齐。

    我们依旧写一个小程序输出struct st3类型变量各个成员变量地址和结构体总大小。

    int main() {
        struct st3 st_val3;
        printf("sizeof(struct st3) = %d\n", sizeof(struct st3));
        printf("st_val3 addr = %p\n", &st_val3);
        printf("st_val3.a1 addr = %p\n", &st_val3.a1);
        printf("st_val3.a2 addr = %p\n", &st_val3.a2);
        printf("st_val3.a3 addr = %p\n", &st_val3.a3);
        printf("st_val3.a4 addr = %p\n", &st_val3.a4);
        printf("st_val3.a5 addr = %p\n", &st_val3.a5);
    
        return 0;
    }
    

    编译运行输出:

    sizeof(struct st3) = 24
    st_val3 addr = 0x7ffeed0c33b0
    st_val3.a1 addr = 0x7ffeed0c33b0
    st_val3.a2 addr = 0x7ffeed0c33b4
    st_val3.a3 addr = 0x7ffeed0c33b6
    st_val3.a4 addr = 0x7ffeed0c33b8
    st_val3.a5 addr = 0x7ffeed0c33c0
    

    从输出我们可以看出,和我们分析的完全一样。

    枚举类型变量和联合体类型变量都可以作为结构体的成员变量,在分析这些结构体占用大小时,分析方法和我们上面的一模一样,只需要把内部任何一种数据类型变量当做一个普通变量看待即可,但是结构体类型成员变量有点不一样,它不适用于结论2,我们举个例子。

    struct st4{
        char a1[3];
        int a2;
        long a3;
        struct st3 a4;
    };
    

    在struct st4中我们定义了一个struct st3类型成员变量,前面我们已经分析过了struct st3占用24个字节。成员变量a1占用3个字节,成员变量a2占用4个字节,所以a2存储在偏移4的地址上,在a1后面填充一个字节。成员变量a3占用8个字节,则a3存储在偏移8的地址上。那么结构体总共占用字节数大小是:8   8 24 = 40。

    最后我们写一个程序验证一下是否如此。

    int main() {
        struct st4 st_val4;
        printf("sizeof(struct st4) = %d\n", sizeof(struct st4));
        printf("st4 addr = %p\n", &st_val4);
        printf("st_val4.a1 addr = %p\n", &st_val4.a1);
        printf("st_val4.a2 addr = %p\n", &st_val4.a2);
        printf("st_val4.a3 addr = %p\n", &st_val4.a3);
        printf("st_val4.a4 addr = %p\n", &st_val4.a4);
    
        return 0;
    }
    

    编译运行输出:

    sizeof(struct st4) = 40
    st4 addr = 0x7ffeec1263a0
    st_val4.a1 addr = 0x7ffeec1263a0
    st_val4.a2 addr = 0x7ffeec1263a4
    st_val4.a3 addr = 0x7ffeec1263a8
    st_val4.a4 addr = 0x7ffeec1263b0
    

    和我们分析的一模一样。

    声明:

    本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

    展开全文
  • //4字节 double b; //8字节 char c; //1字节 int d; //4字节 }; 如果简单的相加,得出来data的size大小应该是17bytes, 但用代码检查答案却是24bytes! std::cout << sizeof(data) << std::endl; ...

    先举一个案例:

    struct data {
    	int a;	//4字节
    	double b;	//8字节
    	char c;	//1字节
    	int d; //4字节
    };
    

    如果简单的相加,得出来data的size大小应该是17bytes,
    但用代码检查答案却是24bytes!

    std::cout << sizeof(data) << std::endl;
    

    本质很简单,抓住内存对齐这个概念,即:
    结构体内的数据成员的起始地址,必然是该数据成员类型的整数倍!
    比如说a是int型(4字节),所以起始地址必然是4的倍数。

    所以让我们来计算一下:
    a的起始地址为0,符合条件;
    b的起始地址为4(0+4),不符合条件,所以需要往后偏移4字节,新起始地址为8;
    c的起始地址为16(8+8),符合条件;
    d的起始地址为17(16+1),不符合条件,所以需要往后偏移3字节,新起始地址为20。
    总计20+4 = 24字节。

    至于为什么要进行内存对齐,原因有以下两点:

    1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
    2. 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。(注:这一点原因涉及计算机组成原理中的指令周期,属于硬件方面的知识)

    参考链接:

    1. C语言中结构体占用内存问题 https://www.cnblogs.com/kl2blog/p/6908048.html
    2. 什么是内存对齐?为什么要内存对齐?https://blog.csdn.net/weixin_40853073/article/details/81451792
    展开全文
  • C语言结构体占用字节数及存储与空间分配我们都知道在数据类型中,char类型占1个字节,short占2个字节,int占4个字节,long占8个字节等等。在计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元...

    【C语言】结构体占用字节数及存储与空间分配

    我们都知道在数据类型中,char类型占1个字节,short占2个字节,int占4个字节,long占8个字节等等。

    在计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体中最大基本类型的大小,下面我们看几个例子:

    1.

    struct A{char a;int b;short c;}str1;

    这里char占1个字节,int占4个字节,short占2个字节,按单元存放如下图:

    1  2  3  4

    a

    b

    b

    b

    b

    c

    c

    由于a占用了1个字节,b存不下,所以开辟新的单元存放b,然后再开辟新的单元存放c。

    从这里可以看出结构体在内存中是按单元存放的,总占用字节数就是3*4=12。

    2.

    struct B{char a;short c;int b;}str2;

    存放如图:

    1  2  3  4

    a

    c

    c

    b

    b

    b

    b

    在这里由于b占用4个字节,而a和c总共才占用3个字节,足够c存放,所以c存放在a的后面,再开辟新的单元存放b。

    此例中占用字节数为2*4=8。

    3.

    struct c{char a;char b[2];char c[4];}str3;

    存放如图:

    1  2  3  4  5  6  7

    a

    b

    b

    c

    c

    c

    c

    这里由于数据类型都为char类型,故不必再开辟新的单元,一行存完。

    占用字节数为1*1+2*1+4*1=7。

    综上所述,结构体在内存中存放是按单元存放的,所开辟单元的最大长度取决于占字节最大的数据类型,此外我们可以发现存储顺序对空间的使用率有一定的影响。

    从以上三例可以看出,第一种最浪费空间;第三种最节省空间,但全使用相同类型,丢失了字段本生的数据类型,不方便使用;第二种介于第一种和第三种写法之间,其空间上比较紧凑,同时又保持了结构体中字段的数据类型。大家可以尝试用sizeof()去深入了解结构体中的按单元存放。

    展开全文
  • 在计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体中最大基本类型的大小,下面我们看几个例子: 1. struct A{ char a; int b; short c;}str1; 这里char占...
  • C语言结构体占用内存长度的计算方法
  • 结bai构体的数据类型的有点多我们就不啰嗦了,直du接来看相同数据结构体的几种书zhi写的格式吧。 格式一: struct tagPhone { char A; int B; short C; }Phone; 格式二: struct tagPhone { char A; short C; ...
  • 在计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体中最大基本类型的大小,下面我们看几个例子:1.struct A{char a;int b;short c;}str1;这里char占1个字节,int占...
  • 结构体的数据类型的有点多我们就不啰嗦了,直接来看相同数据结构体的几种书写的格式吧。格式一:01.structtagPhone02.{03.charA;04.intB;05.shortC;06.}Phone;格式二:01.structtagPhone02.{03.charA;04.shortC;05....
  • C语言结构体占用内存问题 普通数据类型比如int char float 我们很清楚知道它们占用几个内存,比如int占用4个字节,char占用一个字节等等,知道数据类型占用多少内存是很重要的,可以使我们的程序效率更高、运行...
  •  那么我们可能会犯一个错误就是直接1+4+2=7,该结构体占用7个字节。这是错的。  以下我们简单分析下:  计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体...
  • 结构体类型占用的内存空间的计算方法: 首先需要确定是在32位系统,还算在64位系统  是所有成员的内存的和,但是需要注意,默认情况下是按照32位4字节对齐的,64位系统是根据最大变量的长度确定对齐的,如果...
  • 如果不考虑或者不存在内存对齐问题,这个结构体应该占1+4+1 = 6个字节,然而事实上它占了12个字节,???,这就涉及到内存对齐问题了。 结构体中的成员可以是不同的数据类型,成员按照定义时的顺序依次存储在连续...
  • 结构体(struct)类型占用的内存空间的计算方法: 首先需要确定是在32位系统,还算在64位系统  是所有成员的内存的和,但是需要注意,默认情况下是按照32位4字节对齐的,64位系统是根据最大变量的长度确定对齐的,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 515
精华内容 206
关键字:

c语言结构体占用字节

c语言 订阅