共计 3423 个字符,预计需要花费 9 分钟才能阅读完成。
sizeof()计算构造体的大小
简要阐明:构造体成员依照定义时的程序顺次存储在间断的内存空间,然而构造体的大小并不是 * 简略的把所有成员大小相加,而是遵循肯定的规定,须要思考到零碎在存储构造体变量时的地址对齐问题。*
没有成员的构造体占用的空间是多少个字节
答案是:1 个字节。
这就是实例化的起因(空类同样能够被实例化),每个实例在内存中都有一个举世无双的地址,为了达到这个目标,编译器往往会给一个空类或空构造体(C++ 中构造体也可看为类)隐含的加一个字节,这样空类或空构造体在实例化后在内存失去了举世无双的地址,所以空类所占的内存大小是 1 个字节。
首先介绍一个相干的概念——偏移量
struct stru
{
int a; //start address is 0
char b; //start address is 4
int c; //start address is 8
};//12 个字节
偏移量指的是构造体变量中成员的地址和构造体变量地址的差。构造体大小等于最初一个成员的偏移量加上最初一个成员的大小。显然,构造体变量中第一个成员的地址就是构造体变量的首地址。比方下面的构造体,第一个成员 a 的偏移量为 0。第二个成员 b 的偏移量是第一个成员的偏移量加上第一个成员的大小(0+4), 其值为 4;第三个成员 c 的偏移量是第二个成员的偏移量应该是加上第二个成员的大小(4+1)。12
在理论中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条准则:
(1)构造体变量中成员的偏移量必须是成员大小的整数倍(0 被认为是任何数的整数倍)
(2)构造体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。
struct stru1
{
int a; //start address is 0
char b; //start address is 4
int c; //start address is 8
};
PS: 用 sizeof 求该构造体的大小,发现值为 12。int 占 4 个字节,char 占 1 个字节,后果应该是 9 个字节才对啊,为什么呢?这个例子中前两个成员的偏移量都满足要求,但第三个成员的偏移量为 5,并不是本身 (int) 大小的整数倍。编译器在解决时会在第二个成员前面补上 3 个空字节,使得第三个成员的偏移量变成 8。构造体大小等于最初一个成员的偏移量加上其大小,下面的例子中计算出来的大小为 12,满足要求。52
struct stru2
{
int i; //start address is 0
short m; //start address is 4
};
struct stru3
{
char i; //start address is 0
int m; //start address is 4
char n; //start address is 8
};
struct stru4
{
char i; //start address is 0
char n; //start address is 1
int m; //start address is 4
};
尽管构造体 stru3 和 stru4 中成员都一样,但 sizeof(struct stru3)的值为 12 而 sizeof(struct stru4)的值为 8。
由此可见,构造体类型须要思考到字节对齐的状况,不同的程序会影响构造体的大小。
对于嵌套的构造体,须要将其开展。对构造体求 sizeof 时,上述两种准则变为:
(1)开展后的构造体的第一个成员的偏移量该当是被开展的构造体中最大的成员的整数倍。
(2)构造体大小必须是所有成员大小的整数倍,这里所有成员计算的是开展后的成员,而不是将嵌套的构造体当做一个整体。
struct stru5
{
short i; //4
struct
{
char c;
int j;
} tt; //12
int k; //16
};
struct array
{
float f; //4
char p; //8
int arr[3]; //4*3=12
};
其值为 20。float 占 4 个字节,到 char p 时偏移量为 4,p 占一个字节,到 int arr[3]时偏移量为 5,扩大为 int 的整数倍,而非 int arr[3]的整数倍,这样偏移量变为 8,而不是 12。后果是 8 +12=20,是最大成员 float 或 int 的大小的整数倍。
C
//#ifndef __cplusplus
//#endif
#include <iostream>
#include "stdio.h"
#include <stdlib.h>
using namespace std;
struct stru_empty
{ };
struct stru1
{
int a; //start address is 0
char b; //start address is 4
int c; //start address is 8
};
struct stru2
{
int i; //start address is 0
short m; //start address is 4
};
struct stru3
{
char i; //start address is 0
int m; //start address is 4
char n; //start address is 8
};
struct stru4
{
char i; //start address is 0
char n; //start address is 1
int m; //start address is 4
};
struct stru5
{
short i;
struct
{
char c;
int j;
} ss;
int k;
};
struct stru6
{
char i;
struct
{
char c;
int j;
} tt;
char a;
char b;
char d;
char e;
int f;
};
struct stru7
{
char i;
struct
{
char c;
//int j;
} tt;
char a;
char b;
char d;
char e;
int f;
};
struct array
{
float f;
char p;
int arr[3];
};
int main()
{
struct stru6 st6;
struct stru7 st7;
struct array ar;
printf("sizof(char)=%d \n",sizeof(char));
printf("sizof(int)=%d \n",sizeof(int));
printf("sizof(short int)=%d \n",sizeof(short int));
printf("sizof(long int)=%d \n",sizeof(long int));
printf("sizof(long)=%d \n",sizeof(long));
printf("sizof(float)=%d \n\n",sizeof(float));
printf("sizof(stru_empty)=%d \n",sizeof(stru_empty));
printf("sizof(stru1)=%d \n\n",sizeof(stru1));
printf("sizof(stru2)=%d \n\n",sizeof(stru2));
printf("sizof(stru3)=%d \n\n",sizeof(stru3));
printf("sizof(stru4)=%d \n\n",sizeof(stru4));
printf("sizof(stru5)=%d \n\n",sizeof(stru5));
printf("sizof(stru6)=%d \n",sizeof(stru6));
printf("sizof(stru6.tt)=%d \n",sizeof(st6.tt));
printf("the address of stru6.i=%d \n",&st6.i);
printf("the address of stru6.a=%d \n\n",&st6.a);
printf("sizof(stru7)=%d \n",sizeof(stru7));
printf("sizof(stru7)=%d \n",sizeof(st7.tt));
printf("the address of stru7.i=%d \n",&st7.i);
printf("the address of stru7.a=%d \n\n",&st7.a);
printf("sizof(ar)=%d \n",sizeof(ar));
printf("sizof(ar.f)=%d \n",sizeof(ar.f));
printf("sizof(ar.arr)=%d \n",sizeof(ar.arr));
return 0;
}