struct结构体大小的计算(内存对齐)
本次实验环境
环境1:Win10, QT 5.12
一. 背景
当普通的类型无法满足我们的需求的时候,就需要用到结构体了。结构体可衍生出结构体数组,结构体还可以嵌套结构体,这下子数据类型就丰富多彩了,我们可以根据需要定义自己的数据类型。有时需要求结构体的大小,这就涉及到内存对齐的知识。概念、理论之类,我没有深入研究,这里主要是验证一下计算结构体大小的方法,证明学习到的方法确实有效。关于内存对齐,最开始是看了《深入理解计算机系统》中关于“数据对齐”一节,上面轻描淡写的写了下求结构体的大小,我没看明白。看《零基础入门C语言》中关于计算结构体大小的规则,算是看明白了。
二. 前奏
先说点我觉得有意思的地方。数组之间是不可以直接赋值的,但是用结构体包装一下,就达到了这个效果,前者无法做到的事情却通过结构体做到了。通过代码来验证一下。
定义了两个数组arr和arr2,第14行代码,将arr赋值给arr2,编译时会报错。提示:14: error: array type 'int [5]' is not assignable。
(数组名有二义性,一是表示数组名,相当于数组的定海神针,二是表示首元素的地址。第14行代码把一个数组的首元素的地址赋值给另一个数组首元素,显然这是不允许的)
将第14行代码注释后。定义了一个结构体,里面定义了一个整型数组。然后定义了两个结构体变量tt1和tt2,将tt2赋值给了tt1,然后打印变量tt2中数组里面的每个元素。
1 #include <iostream>
2
3 using namespace std;
4
5 struct numArr
6 {
7 int m_arr[5];
8 };
9
10 int main()
11 {
12 int arr[5] = {1, 2, 3, 4, 5};
13 int arr2[5] = {0};
14 // arr2 = arr;
15
16 struct numArr tt1 = {{1, 2, 3, 4, 5}};
17 struct numArr tt2 = {{0}};
18 tt2 = tt1;
19
20 for(int i = 0; i < 5; ++i)
21 {
22 cout<<tt2.m_arr[i]<<endl;
23 }
24
25
26
27 return 0;
28 }
运行结果如下
从结果可以看到,打印结构与tt1中的数组中的元素一致。也就是说,将结构体变量tt1赋值给tt2后,tt2中的数组与tt1中的数组也一样了。
通过结构体这么一包装,就产生了数组"可以"赋值的现象了,挺有意思的。
三. 结构体大小的计算
内存对齐,关于这一点,《深入理解计算机系统》这本书用的篇幅蛮少的,两页不到。书上是这么介绍的。
许多计算机系统对基本数据类型的合法地址做出了一些限制,要求某种类型对象的地址必须是某个值K(通常是2、4或8)的倍数。这种对齐限制简化了形成处理器和内存系统之间的接口的硬件设计。
前半句能理解,后半句,涉及硬件的东西,懵逼了。
《零基础入门C语言》这本书,从现象的角度阐述,它先讲内存不对齐的情况。
一个成员变量需要多个机器周期去读的现象,称为内存不对齐。为什么要对齐呢?本质是牺牲空间,换取时间的方法。
一般来说,大多数系统,即使不对齐,也没什么大的问题,只是原本需要一次进行内存操作读或写,现在需要两次或多次了。不过这个与硬件有关系,比如有些处理器对于某些指令有特定的要求,否则可能就真的出现异常了。有兴趣的话,建议自行去深入学习。
对齐规则/计算方法
x86(Linux默认#pragma pack(4), Window默认#pragma pack(8))。Linux最大支持4字节对齐。
方法:
1) 取pack(n)的值 (n = 1, 2, 4,8......),取结构体中类型最大值为m。两者取小即为外对齐大小 Y = (m < n ? m: n);
2) 将每一个结构体的成员大小与Y比较取小者为X,作为内对齐的大小;
3) 所谓按X对齐,即为地址(设起始地址为0)能被X整除的地方开始存放数据;
4) 外部对齐原则是依据Y的值(Y的最小整数倍),进行补空操作;
以上就是通常计算结构体大小的方法了。接下来,我们通过一些简单实验来验证一下。
首先,定义一个结构体,里面包含了char、short、int类型的变量。
1) 结构体先按照char、short、int的顺序定义。然后定义一个结构体变量s1,求结构体的大小,一个是结构体类型的大小(模子),一个是是结构体变量的大小。我们也可以把结构体成员的地址也打印出来,查看它们的偏移量,分析起来会更清晰一些。
1 #include <stdio.h>
2
3 typedef struct stu
4 {
5 char a;
6 short b;
7 int c;
8 } Stu;
9
10 int main()
11 {
12 Stu s1 = {'m', 1, 20};
13 printf("sizeof(Stu) = %d\n", sizeof(Stu));
14 printf("sizeof(s1) = %d\n", sizeof(s1));
15
16 printf("-----------\n");
17 printf("&s1 = %p\n", &s1);
18 printf("&s1.a = %p\n", &s1.a);
19 printf("&s1.b = %p\n", &s1.b);
20 printf("&s1.c = %p\n", &s1.c);
21 return 0;
22 }
a) Windows平台,pack默认为8。先求外对齐大小Y,结构体中类型最大的为int类型,大小为4字节,4比8小,所以Y值为4.
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。结构体中成员分别为char 1字节,short 2字节,int 4字节,与4(外对齐大小Y)比较,得到内对齐大小分别为 1, 2, 4。
c) 假设起始地址为0x00,0可以被1整除,可以存放a了。a为char类型,大小为1个字节。接着地址为0x01,但是0x01不能被2整除,然后下一个地址为0x02,0x022可以被2整除,因此b的起始地址为0x02(此时,a与b之间填充了一个字节)。b为short类型,大小为2个字节。接着地址到了0x04,它可以被4整除,于是可以存放c了,c为int类型,大小为4个字节。
d) 接着地址到了0x08,(0x08-0x00)它可以被4(外对齐大小Y)整除,满足外对齐要求。
经分析,结构体大小为1 + 1 + 2 + 4 = 8个字节。
图如下图所示
代码运行结果如下
从打印结果来看,结构体大小为8,与上面的分析结果一致,符合预期。
2) 调整结构体中成员的顺序。结构体先按照short、char、int的顺序定义。打印成员地址的时候也需要调整下a与b的打印顺序。代码其它部分保持不变。
1 typedef struct stu
2 {
3 short b;
4 char a;
5 int c;
6 } Stu;
a) Windows平台,pack默认为8。先求外对齐大小Y,结构体中类型最大的为int类型,大小为4字节,4比8小,所以Y值为4。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。结构体中成员分别为short 2字节,char 1字节,int 4字节,与4(外对齐大小Y)比较,得到内对齐大小分别为 2,1, 4。
c) 假设起始地址为0x00,0可以被2整除,可以存放b了。b为short类型,大小为2个字节。接着地址为0x02,2可以被1整除,a为char类型,大小为一个字节。然后下一个地址为0x03,0x03不可以被4整除,接着地址为0x04(此时,b与c之间填充了一个字节)。0x04可以被4整除,于是可以存放c了,c为int类型,大小为4个字节。
d) 接着地址到了0x08,(0x08-0x00)它可以被4(外对齐大小Y)整除,满足外对齐要求。
经分析,结构体大小为2 + 1 + 1 + 4 = 8个字节。
图如下图所示
代码运行结果如下.
结构体大小为8,符合预期。
3)调整结构体中成员的顺序。结构体先按照int、short、char的顺序定义。打印成员地址的时候也需要调整为c、b、a的打印顺序。代码的其它部分保持不变。
1 typedef struct stu
2 {
3 int c;
4 short b;
5 char a;
6
7 } Stu;
a) Windows平台,pack默认为8。先求外对齐大小Y,结构体中类型最大的为int类型,大小为4字节,4比8小,所以Y值为4。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。结构体中成员分别为int 4字节,short 2字节,char 1字节,与4(外对齐大小Y)比较,得到内对齐大小分别为4, 2,1。
c) 假设起始地址为0x00,0x00可以被4整除,可以存放c了。c为int类型,大小为4个字节。接着地址为0x04,0x04可以被2整除,b为short类型,大小为两个字节。然后下一个地址为0x06,0x06可以被1整除,可以存放a,a大小为1个字节。
d) 接着地址到了0x07,(0x07-0x00)不能被4(外对齐大小Y)整除,为满足外对齐要求,后面需要填充1个字节。
经分析,结构体大小为:4 + 2 + 1 + 1 = 8个字节。
图示如下
运行结果如下
结构体大小为8,符合预期。
实验调整
将pack修改为1,在前面三个实验的基础上,再验证一下,看下使用这个规则是否与实际情况一致,在代码前面添加
1 #pragma pack(1)
4) 结构体与1)中一致,按照char、short、int的顺序定义。打印成员地址也是按照a、b、c这个次序打印。
1 #pragma pack(1)
2
3 typedef struct stu
4 {
5 char a;
6 short b;
7 int c;
8 } Stu;
a) 现在pack为1。先求外对齐大小Y,结构体中类型最大的为int类型,大小为4字节,1比4小,所以Y值为1。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。结构体中成员分别为char 1字节,short 2字节,int 4字节,与1(外对齐大小Y)比较,得到内对齐大小分别为 1, 1, 1。
c) 假设起始地址为0x00,0x00可以被1整除,可以存放a了。a为char类型,大小为1个字节。接着地址为0x01,1可以被1整除,可以存放b了,b的类型为short类型,大小为2个字节。然后下一个地址为0x03,0x03可以被1整除,可以存放c了。c为int类型,占4个字节。
d) 接着下一个地址为0x07,(0x07-0x00)可以被1(外对齐大小Y)整除,满足外对齐的要求。
经分析,结构体大小为1 + 2 + 4 = 7个字节。
图如下图所示
运行结果如下
结构体大小为7,符合预期。
5) 调整结构体中成员的顺序。结构体按照short、char、int的顺序定义。打印成员地址的时候也需要调整下a与b的打印顺序。代码的其它部分不变。
1 #pragma pack(1)
2
3 typedef struct stu
4 {
5 short b;
6 char a;
7 int c;
8 } Stu;
a) 现在pack为1。先求外对齐大小Y,结构体中类型最大的为int类型,大小为4字节,1比4小,所以Y值为1。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小X。结构体中成员分别为short 2字节,char 1字节,int 4字节,分别与1(外对齐大小Y)比较,1较小,得到内对齐大小分别为 1,1,1。
c) 假设起始地址为0x00,0x00可以被1整除,可以存放b了。b为short类型,大小为2个字节。接着地址为0x02,0x02可以被1整除,可以存入a了。a为char类型,大小为1个字节。然后下一个地址为0x03,0x03可以被1整除,c的类型为int,c的大小为4个字节。
d) 在c起始地址的基础往后4个字节,现在地址到了0x07,(0x07-0x00)可以被1整除,满足外对齐要求(不需要填充字节了)。
经分析,结构体大小为2 + 1 + 4 =7个字节。
图如下图所示
运行结果如下
结构体大小为7,符合预期。
6) 调整结构体中成员的顺序。结构体按照int、short、char的顺序定义。打印成员地址的时候也需要调整为c、b、a的打印顺序。代码的其它部分不变。
1 #pragma pack(1)
2
3 typedef struct stu
4 {
5 int c;
6 short b;
7 char a;
8 } Stu;
a) pack现在为1。先求外对齐大小Y,结构体中类型最大的为int类型,大小为4字节,1比4小,所以Y值为1。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。结构体中成员分别为int 4字节,short 2字节,char 1字节,分别与1(外对齐大小Y)比较,得到内对齐大小分别为1, 1,1。
c) 假设起始地址为0x00,0x00可以被4整除,可以存放c了。c为int类型,大小为4个字节。接着地址为0x04,0x04可以被1整除,b为short类型,大小为两个字节。然后下一个地址为0x06,0x06可以被1整除,可以存放a了,a为char类型,a大小为1个字节。
d) 接着地址到了0x07,(0x07-0x00)可以被1(外对齐大小Y)整除,满足外对齐要求(不需要填充字节)。
经分析,结构体大小为:4 + 2 + 1 = 7个字节。
图示如下
运行结果如下
结构体大小为7,符合预期。
四.例题演示
有人可能会说了,你举的这几个例子太简单了,有没有复杂的例子可以看下呢?比如结构体中包含数组的情况,这个计算方法是否适用呢?好的,我们就拿《深入理解计算机系统》这本书的习题来验证一下。
书中练习题 3.44 有5道题目,均是求结构体大小与成员的偏移量,我们将其作为案例,按照上述方法验证一下。
对下面的每个结构体声明,确定每个字段的偏移量、结构体总的大小、以及在x86-64下它的对齐要求。
(注:因为书中的案例中K值为8,所以下面的代码示例中将pack均显式设置为了8)
1)
1 struct P1{int i; char c; int j; char d;}
a) K现在为8。先求外对齐大小Y,结构体中类型最大的为int类型,大小为4字节,4比8小,所以Y值为4。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小,取较小者。结构体中成员分别为int 4字节,char 1字节,int 4字节,char 1字节,分别与4(外对齐大小Y)比较,得到内对齐大小分别为4,1,4, 1。
c) 假设起始地址为0x00,0x00可以被4整除,可以存放i了。i为int类型,大小为4个字节。接着地址为0x04,0x04可以被1整除,可以存储c,c为char类型,大小为1个字节。然后下一个地址为0x05,0x05不可以被4整除,最近的能被4整除的地址就是0x08了,需要填充3个字节。于是从0x08开始存放j,j为int类型,j大小为4个字节。下一个地址为0x0c。
d) 0x0c可以被1整除, d为char类型,大小为1个字节,接着地址到了0x0d,(0x0d-0x00)不可以被4(外对齐大小Y)整除,为满足外对齐要求,需要填充3个字节,直到0x10,(0x10-0x00)是Y的整数倍,满足外对齐。
经分析,结构体大小为:4 + 1 + 3 + 4 + 1 + 3 = 16个字节。
i 偏移量 0
c 偏移量 4
j 偏移量 8
d 偏移量 12
图示如下
代码如下,为了避免编译器告警,与前面相比,作了调整,进行了强制类型转换。
1 #pragma pack(8)
2
3 #include <stdio.h>
4
5 typedef struct P1{int i; char c; int j; char d;} PP1;
6
7 int main()
8 {
9 PP1 p;
10 printf("sizeof(P1) = %d\n", (int)sizeof(PP1));
11 printf("sizeof(p) = %d\n", (int)sizeof(p));
12
13 printf("&p = %p\n", (void *)&p);
14 printf("&p.i = %p\n", (void *)&p.i);
15 printf("&p.c = %p\n", (void *)&p.c);
16 printf("&p.j = %p\n", (void *)&p.j);
17 printf("&p.d = %p\n", (void *)&p.d);
18
19 return 0;
运行结果如下
i,c, j,d的偏移量分别为0, 4, 8, 12,符合预期。
2)
1 struct P2 {int i; char c; char d; long j;};
a) K现在为8。先求外对齐大小Y,结构体中类型最大的为long类型,我这台电脑上long大小为4字节,4比8小,所以Y值为4。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。结构体中成员分别为int 4字节,char 1字节,char 1字节,long 4字节,分别与4(外对齐大小Y)比较,取较小者,得到内对齐大小分别为4,1,1, 4。
c) 假设起始地址为0x00,0x00可以被4整除,可以存放i了。i为int类型,大小为4个字节。接着地址为0x04,0x04可以被1整除,可以存储c。c为char类型,大小为1个字节。然后下一个地址为0x05,0x05可以被1整除,可以存储d。d的类型为char,大小为1个字节。接下来地址为0x06,0x06不能被4整除,最近能被4整除的地址为0x08,需要填充2个字节,才能到0x08。j为long类型,j大小为4个字节。
d) 接着地址到了0x0c,(0x0c-0x00)可以被4(外对齐大小Y)整除,满足外对齐。
经分析,结构体大小为:4 + 1 + 1 + 2 + 4 = 12个字节。
i 偏移量 0
c 偏移量 4
d 偏移量 5
j 偏移量 8
图示如下:
代码如下
1 #include <stdio.h>
2
3 #pragma pack(8)
4
5 typedef struct P2
6 {
7 int i;
8 char c;
9 char d;
10 long j;
11 } PP2;
12
13 int main()
14
15 {
16 printf("sizeof(long) = %d\n", (int)sizeof(long));
17
18 PP2 p;
19 printf("sizeof(P1) = %d\n", (int)sizeof(PP2));
20 printf("sizeof(p) = %d\n", (int)sizeof(p));
21
22 printf("&p = %p\n", (void *)&p);
23 printf("&p.w = %p\n", (void *)&p.i);
24 printf("&p.c = %p\n", (void *)&p.c);
25 printf("&p.c = %p\n", (void *)&p.d);
26 printf("&p.c = %p\n", (void *)&p.j);
27
28 return 0;
29 }
运行结果如下
i,c,d,j的偏移量分别为0,4,5,8,符合预期。
3)若结构体中有数组,如何整?
1 struct P3{short w[3]; char c[3]};
a) K现在为8。先求外对齐大小Y。若有数组,取数组中元素的类型。结构体中类型最大的是short类型,大小为2字节,2比8小,所以Y值为2。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。若结构体成员为数组,取成员整体的大小。结构体中成员分别为w 6字节,c 3字节,分别与2(外对齐大小Y)比较,得到内对齐大小分别为2,2。
c) 假设起始地址为0x00,0x00可以被2整除,可以存放w了。w为short数组类型,大小为6个字节。接着地址为0x06,可以被3整除,可以存储c,c为char数组类型,大小为3个字节。
d) 接着地址到了0x09,(0x09-0x00)不可以被2(外对齐大小Y)整除,为满足外对齐要求,需要填充1个字节,直到0x0a,(0x0a-0x00)是Y的整数倍,满足外对齐。
经分析,结构体大小为:6 + 3 + 1 = 10个字节。
w偏移量 0
c偏移量 6
通过代码验证一下,代码如下
1 #include <stdio.h>
2
3 #pragma pack(8)
4
5 typedef struct P3{short w[3]; char c[3];} PP3;
6
7 int main()
8
9 {
10 PP3 p;
11 printf("sizeof(P1) = %d\n", (int)sizeof(PP3));
12 printf("sizeof(p) = %d\n", (int)sizeof(p));
13
14 printf("&p = %p\n", (void *)&p);
15 printf("&p.i = %p\n", (void *)&p.w);
16 printf("&p.c = %p\n", (void *)&p.c);
17
18 return 0;
19 }
运行结果如下
w,c的偏移量分别为0,6,符合预期。
4) 如果来个指针数组呢?
1 struct P4{short w[5]; char *c[3];};
a) K现在为8。先求外对齐大小Y。若有数组,取数组中元素的类型。结构体中类型最大的是指针类型,大小为8字节,8与8相等,所以Y值为8。
b) 然后将结构体中的每一个成员与Y进行比较,依次求内对齐的大小。若结构体成员为数组,取成员整体的大小。结构体中成员分别为w 10字节,c 24字节,分别与8(外对齐大小Y)比较,得到内对齐大小分别为8,8。
c) 假设起始地址为0x00,0x00可以被8整除,可以存放w了。w为short数组类型,大小为10个字节。接着地址为0x0a,不可以被8整除,需要填充6个字节,地址到了0x10,这才可以存储c。c为指针数组类型,大小为24个字节。
d) 接着地址到了0x28,(0x28-0x00)可以被8(外对齐大小Y)整除,满足外对齐。
w 偏移量 0
c 偏移量 16
经分析,结构体大小为:10 + 6 + 24 = 40个字节。这个图有些大,就不放图片了。
通过代码验证一下,代码如下
1 #include <stdio.h>
2
3 #pragma pack(8)
4
5 typedef struct P4
6 {
7 short w[5];
8 char *c[3];
9 } PP4;
10
11 int main()
12
13 {
14 PP4 p;
15 printf("sizeof(P1) = %d\n", (int)sizeof(PP4));
16 printf("sizeof(p) = %d\n", (int)sizeof(p));
17
18 printf("&p = %p\n", (void *)&p);
19 printf("&p.w = %p\n", (void *)&p.w);
20 printf("&p.c = %p\n", (void *)&p.c);
21
22 return 0;
23 }
运行结果如下
w,c的偏移量分别为0, 16,符合预期。
5)假如结构体中嵌套结构体,这个方法还适用吗?那再来验证一波。
1 typedef struct P5
2 {
3 struct P3 a[2];
4 struct P2 t;
5 } PP5;
看起来有点复杂,不过还是用同样的方法。
a) K现在为8。先求外对齐大小Y。若有数组或结构体,取数组或结构体中成员的类型。结构体中类型最大的是long类型,大小为4字节,4比8比小,所以Y值为4。
b) 然后将结构体PP5中的每一个成员与Y进行比较,依次求内对齐的大小。若结构体成员为数组或结构体,取成员整体的大小。前面已经求出,结构体中成员分别为a 20字节,t 12字节,分别与4(外对齐大小Y)比较,得到内对齐大小分别为4,4。
c) 假设起始地址为0x00,0x00可以被4整除,可以存放a了。a为结构体数组,大小为20个字节。接着地址为0x14,0x14可以被4整除,可以存储t。t为结构体类型,大小为12个字节。
d) 接着地址到了0x20,(0x20-0x00)可以被4(外对齐大小Y)整除,满足外对齐。
a 偏移量 0
t 偏移量 20
经分析,结构体大小为:20 + 12 = 32个字节。
通过代码验证一下,代码如下
1 #include <stdio.h>
2
3 #pragma pack(8)
4
5 struct P2
6 {
7 int i;
8 char c;
9 char d;
10 long j;
11 };
12
13 struct P3
14 {
15 short w[3];
16 char c[3];
17 };
18
19 typedef struct P5
20 {
21 struct P3 a[2];
22 struct P2 t;
23 } PP5;
24
25 int main()
26
27 {
28 printf("sizeof(long) = %d\n", (int)sizeof(long));
29
30 PP5 p;
31 printf("sizeof(PP5) = %d\n", (int)sizeof(PP5));
32 printf("sizeof(p) = %d\n", (int)sizeof(p));
33
34 printf("&p = %p\n", (void *)&p);
35 printf("&p.a = %p\n", (void *)&p.a);
36 printf("&p.t = %p\n", (void *)&p.t);
37
38 return 0;
39 }
运行结果如下
a,t的偏移量分别为0, 20,符合预期。
五.结语
目前,已经验证了结构体中包含基本数据类型,结构体中包含数组,结构体中包含结构体(结构体嵌套)的情形,可能出现的情况都验证完了,也证实了书中的方法的确有效。感谢前辈们总结的经验。
注:如果你在做《深入理解计算机系统》书上练习题时,会发现书中提供的3.44 中B和E两题练习题答案与我上面的结果不一致。不要慌,我对比了下,原因很可能是作者的机器中long类型是8字节,而我的机器中long类型是4字节。依据之一请参见书中P27页"字数据大小"一节,依据二,根据两种不同大小的long类型,分别进行计算与验证,这里就不赘述了。
参考材料
1.《深入理解计算机系统》布莱恩特,奥哈拉伦
2.《零基础入门C语言》 王桂林
struct结构体大小的计算(内存对齐)的更多相关文章
- C语言地址对齐(转)--网络编程之结构体大小的计算
什么是地址对齐? 现代计算机中内存空间都是按照字节(byte)划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数 ...
- 关于C语言中结构体大小计算
结构体大小的计算,.网上说法一大堆还都不一样分什么对齐不对齐,偏移量什么的.. 在此稍微举例简单总结下: 对齐原则:每一成员的结束偏移量需对齐为后一成员类型的倍数 补齐原则:最终大小补齐为成员中最大 ...
- C++字节对齐与结构体大小计算
转载注明出处:http://pppboy.blog.163.com/blog/static/30203796201082494026399/ 感谢原创博主的辛勤成果. 说明: 结构体的sizeof值, ...
- Windows下struct和union字节对齐设置以及大小的确定(一 简介和结构体大小的确定)
在windows下设置字节对齐大小的方式,目前我了解有三种: 1. 在编译程序时候的编译选项 /Zp[n],如 cl /Zp4 表示对齐大小是4字节: 2. 预处理命令 #pragma pack ...
- C/C++ sizeof函数解析——解决sizeof求结构体大小的问题
C/C++中不同数据类型所占用的内存大小 32位 64位 char 1 1 int ...
- NumPy-快速处理数据--ndarray对象--多维数组的存取、结构体数组存取、内存对齐、Numpy内存结构
本文摘自<用Python做科学计算>,版权归原作者所有. 上一篇讲到:NumPy-快速处理数据--ndarray对象--数组的创建和存取 接下来接着介绍多维数组的存取.结构体数组存取.内存 ...
- C语言中结构体大小计算
1.普通结构体 struct student { char sex; char a; char b; int age; char name[100]; }; 该结构体大小为108 解答:1.先算str ...
- <转> Struct 和 Union区别 以及 对内存对齐方式的说明
转载地址:http://blog.csdn.net/firefly_2002/article/details/7954458 一.Struct 和 Union有下列区别: 1.在存储多个成员信息时,编 ...
- 从gcc的__attribute__((packed))聊到结构体大小的问题
公司的前辈的代码里面 结构体的花括号最后 有__attribute__((packed))字样.以前没见过,所以查了查.学习学习http://blog.sina.com.cn/s/blog_559f6 ...
随机推荐
- BeanUtils实现对象拷贝(三)
package beanutil; import java.lang.reflect.InvocationTargetException; import java.util.Date; import ...
- 回顾games101中的SSAA和MSAA
回顾games101中的AA(抗锯齿) 前言 善于进行课后总结,可以更加巩固自己的知识和具体细节 锯齿(走样)产生的原因 本质上,在光栅化阶段中,用有限离散的数据想表示连续的(类似三角形的某一边),就 ...
- nginx 开启,关闭,重启
2021-08-191. 启动 # 判断配置文件是否正确 cd /usr/local/nginx/sbin ./nginx -t # 启动 cd usr/local/nginx/sbin ./ngin ...
- 基于Linux的系统排错
1.系统引导过程概述 2.系统异常及恢复 [1]grub系统引导 1)mbr上446字节丢失 模拟问题: dd if=/dev/zero? of=/dev/vda? bs=446? count=1? ...
- GUI实现超简单的计算器
计算器样式 实现代码 //实现超简易的计算器 public class Test02 { public static void main(String[] args) { Counter counte ...
- CGLib浅析
CGLib浅析 什么是CGLib CGLIB实现动态代理,并不要求被代理类必须实现接口,底层采用asm字节码生成框架生成代理类字节码(该代理类继承了被代理类). 所以被代理类一定不能定义为final ...
- Git - Mac 电脑使用 brew 更新 Git
安装 Homebrew Homebrew 是一个软件包管理器.它的作用就是将软件包安装到自己的目录中,然后将其文件符号链接到 /usr/local.更多信息,请自行进入官网查看 https://bre ...
- k8s架构与组件详解
没有那么多花里胡哨,直接进行一个K8s架构与组件的学习. 一.K8s架构 k8s系统在设计是遵循c-s架构的,也就是我们图中apiserver与其余组件的交互.在生产中通常会有多个Master以实现K ...
- pycharm的常规使用
1.修改当前项目的Py版本,是py2还是py3 pycharm-->settings-->选中要运行的项目-->选择py版本(如果你两个py版本都装在本机的话) 2.显示行数 在每行 ...
- pip更新升级和删除包
pip检测更新命令:pip list –outdated pip升级包命令:pip install --upgrade packagename pip卸载包命令:pip uninstall packa ...