转载于:https://blog.youkuaiyun.com/programmer_at/article/details/49423891作者:猪杂汤饭
https://zhidao.baidu.com/question/183477298 作者:zrrhx
https://blog.youkuaiyun.com/yansj_scu/article/details/45310715 作者: yansj_scu
感谢大佬的详细的撰写!
#include <stdio.h>
int main()
{
//测试结构体大小
typedef struct Student
{
int id;
char name[10];
int score;
}stu;
printf("结构体Student的大小为%d\n", sizeof(Student));
//联合体
union foo{
char s[10]; //对齐单位:1,总长度:10
int a; //对齐单位:4,总长度:4
}Foo1;
printf("联合体的大小为%d\n", sizeof(Foo1));
enum Day{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //变量workday的类型为枚举型enum DAY
printf("enum的大小为%d\n", sizeof(workday));
return 0;
}
一、C语言中sizeof()是一个关键字,不是函数,不需要使用头文件,补足知识:
1、跟int, float关键字一样,编译器自动识别他们;
2、千万不要因为它长得像函数,就上它的当;
3、就像getchar()的返回值是个int型而不是char型一样,C中有很多陷阱一样。
4、基本数据类型长度
二、结构体struct(在没有#pragma pack宏的情况下)
声明一个空的struct 或者union,它们所占的空间都是1B.
1、数据成员对齐规则:第一个数据成员放在offset为0的地方,之后的每个数据成员存储的起始位置要从该成员大小的整数倍开始(例如:int在32位机上为4字节,所以要从4的整数倍地址开始存储)。
struct student1{
char num[10];//对齐单位是:1
}Stu1; //总长:1*10=10
struct student2{
char num[10];//[0]~[9]
int no[10]; //对齐单位是:4 [12]~[51]
}Stu2; //总长:52
2、结构体作为成员:如果一个结构体中同时包含结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(如struct a中有struct b,而b中有char,int,double等元素,那么b应该从8(double类型的大小)的整数倍开始存储。
//结构体内嵌结构体
struct student5{
int id; //对齐单位是:4,[0]~[3]
double score; //对齐单位是:8,[8]~[15]
short grade; //[16]~[17]
Stu4 aa; //对齐单位是:8,[24]~[47]
char name[2]; //[48]~[49]
}Stu5; //总长度应为对齐单位(8)的倍数:56
3、结构体的总大小:即sizeof的结果。
按之前的对齐原则计算出来的大小的基础上,必须还得是其内部最大成员的整数倍,不足的要补齐(如struct中最大为double,现在计算得到的已经是11,则总大小为16)。
struct student3{
int n0[10]; //对齐单位是:4 [0]~[39]
char num[10];//对齐单位是:1 [40]~[49]
}Stu3; //总长度应为最大对齐单位(4)的整数倍:52
typedef struct student4{
int id; //对齐单位是:4,[0]~[3]
double weight; //对齐单位是:8,[8]~[15]
float height; //[16]~[19]
}Stu4; //总长度应为对齐单位(8)的倍数:24
4、注意:即使相同的成员变量,但是排的位置不一样,字节长度也不一定相等。 所以合理地安排成员变量的排序,的确可以节省空间。但是在目前硬件资源越发便宜的今天,这点内存可能就不算的上什么了。
(1)第一种:
最大的对齐单位是4个字节,每个小格代表一个字节,以int型占用4个来作为倍数,因为A占用一个字节后,B放不下,所以开辟新的单元,然后开辟新的单元放C,所以格式一占用的字节数为:3*4=12;
struct tagPhone
{
char A;//[0]
int B;//[4]~[7]
short C;//[8]~[9]
}Phone;//4的整数倍12
A | |||
B | B | B | B |
C | C | C |
内存布局
(2)第二种:A后面还有三个字节,足够C存放,所以C根着A后面存放,然后开辟新单元存放B数据。所以格式二占用的内存字节为2*4=8。
struct tagPhone
{
char A;//[0]
short C;//[2]~[3]
int B;//[4]~[7]
}Phone2; //4的整数倍:8个字节
A | C | C | |
B | B | B | B |
内存布局
三、联合体union
1、联合体:长度为联合中元类型(如数组,取其类型的数据长度)最大的变量长度(对齐单位)的整数倍,且要大于等于其最大成员所占的存储空间
union test{
short s;//2
char c;//1
}; //那么union的在内存中占的长度是sizeof(short)=2B。
//联合体
union foo{
int a; //对齐单位:4,总长度:4
double d; //对齐单位:8,总长度:8
}Foo1; //对齐单位:8,最大存储长度8,因此联合体的长度应为对齐单位的倍数:8
//联合体
union foo{
char s[10]; //对齐单位:1,总长度:10
int a; //对齐单位:4,总长度:4
}Foo1; //对齐单位:8,最大存储长度10,因此联合体的长度应为对齐单位4的倍数:12
//联合体
union foo{
char s[10]; //对齐单位:1,总长度:10
int a; //对齐单位:4,总长度:4
double d; //对齐单位:8,总长度:8
}Foo1; //对齐单位:8,最大存储长度10,因此联合体的长度应为对齐单位8的倍数:16
2、联合体内嵌结构体
//联合体包含结构体
typedef union foo2{
Stu4 bb; //对齐单位:8,总长度:24
char s[10]; //对齐单位:1,总长度:10
int a; //对齐单位:4,总长度:4
double d; //对齐单位:8,总长度:8
}Foo2; //对齐单位:8,长度应为对齐单位的倍数:24
3、结构体内嵌联合体
//结构体包含联合体
struct student6{
char num[10]; //对齐单位:1,[0]~[9]
int no[10]; //对齐单位:4,[12]~[51]
Foo2 cc; //对齐单位:8,[56]~[79]
char a; //对齐单位:1,[80]
double a1; //对齐单位:8,[88]~[95]
int a2; //对齐单位:4,[96]~[99]
}Stu6; //对齐单位:8,长度应为对齐单位的倍数:104
四、枚举enum
1、enum只是定义了一个常量集合,里面没有“元素”,而枚举类型是当做int来存储的,所以枚举类型的sizeof值都为4。
enum Day
{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //变量workday的类型为枚举型enum DAY