【C语言】结构体、联合体、枚举的内存存储方式 | 一篇文章读懂C语言中全部数据结构类型内存对齐、如何高效优化代码内存、提升代码质量

本文详细探讨了C语言中结构体、联合体和枚举的内存分配规则。结构体内存分配遵循对齐原则,影响因素包括成员类型和顺序。联合体的大小以最宽成员为准且可被所有成员类型整除。枚举的内存大小通常与能容纳其最大枚举值的整数类型相同,但在某些情况下可能因超出int范围而扩大。文章还讨论了枚举值超过int范围时可能影响的内存占用,并引用了相关资源进行深入解析。
摘要由CSDN通过智能技术生成

数据结构类型(内存篇)

一.结构体的内存

内存对齐

规则:

1.结构体的第一个数据成员存放的地址为结构体变量偏移量为 0 的地址处.

2.其他起始地址为该类型变量所占内存的整数倍,如果不足部分用数据填充到所占内存的整数倍

3.结构体所占总内存为该结构体的成员中基本数据类型占字节数最大的整数倍

(见图解1-1)

#include<stdio.h>

struct str1 {   // ??
	char a;     //  1 byte  //此处若删除char a 则所占内存为 24 以验证规则 1;(自行验证)
	int b;      //  4 byte
	float c;    //  4 byte
	double d;   //  8 byte(最大)
	char ch;    //  1 byte
}s1;            // 32 byte

//将结构体内部变量调换位置后结构体内存占用发生改变

struct str2 {   // ?? 
	char a;     //  1 byte
	char ch;    //  1 byte
	int b;      //  4 byte
	float c;    //  4 byte
	double d;   //  8 byte(最大)
}s2;            // 24 byte

int main() {
	printf("%d\n",sizeof(s1));  //输出结果:32
	printf("%d\n",sizeof(s2));  //输出结果:24
	return 0;
}
图解1-1

在这里插入图片描述

如果结构体内部含有数组:(见图解1-2)

#include<stdio.h>

// 当结构体成员包含数组:
struct str3 {
	int a;       //  4 byte
	double b;    //  8 byte(最大)  
	char arr[9]; //  9 byte(char基本数据类型占 1byte)
}s3;             //  结果:32

struct str4 {
	double b;    //  8 byte(最大)
	int a;       //  4 byte
	char arr[9]; //  9 byte(char基本数据类型占 1byte)
}s4;             //  结果:24

int main() {
	//如果结构体成员含有数组:
	printf("%d\n", sizeof(s3));  //输出结果:32
	printf("%d\n", sizeof(s4));  //输出结果:24
	return 0;
}
图解1-2

在这里插入图片描述

如果结构体中包含结构体:

#include<stdio.h>

struct str5 {
	char ch;
	short sh;
	int num;
}s5;

struct str6 {
	int n;
	struct str5 s5;
}s6;

struct str7 {
	int n;
	char ch;
	short sh;
	int num;
}s7;

int main() {
	//如果结构体成员包含结构体:
	printf("%d\n", sizeof(s5));  //输出结果:8
	printf("%d\n", sizeof(s6));  //输出结果:12 --> sizeof(int)+8
	printf("%d\n", sizeof(s7));  //输出结果:12
	return 0;
}

结论:结构体 str6 和 str7等价,当结构体中成员包含结构体时 等价于 把成员结构体内容展开

注意:结构体成员包含的结构体不能为本身!

[完整代码如下]
#include<stdio.h>

struct str1 {   //  内部求和为 18byte
	char a;     //  1 byte
	int b;      //  4 byte
	float c;    //  4 byte
	double d;   //  8 byte(最大)
	char ch;    //  1 byte
}s1;            //  结果:32 byte

// 将结构体成员变量调换位置后结构体内存占用发生改变:
struct str2 {   //  内部求和为 18byte
	char a;     //  1 byte
	char ch;    //  1 byte
	int b;      //  4 byte
	float c;    //  4 byte
	double d;   //  8 byte(最大)
}s2;            //  结果:24 byte

// 当结构体成员包含数组:
struct str3 {
	int a;       //  4 byte
	double b;    //  8 byte(最大)  
	char arr[9]; //  9 byte(char基本数据类型占 1byte)
}s3;             //  结果:32

struct str4 {
	double b;    //  8 byte(最大)
	int a;       //  4 byte
	char arr[9]; //  9 byte(char基本数据类型占 1byte)
}s4;             //  结果:24

// 当结构体成员包含结构体:
struct str5 {
	char ch;
	short sh;
	int num;
}s5;

struct str6 {
	int n;
	struct str5 s5;
}s6;

struct str7 {
	int n;
	char ch;
	short sh;
	int num;
}s7;

int main() {

	printf("%d\n",sizeof(s1));  //输出结果:32
	printf("%d\n",sizeof(s2));  //输出结果:24
	printf("\n");
	//如果结构体成员含有数组:
	printf("%d\n", sizeof(s3));  //输出结果:32
	printf("%d\n", sizeof(s4));  //输出结果:24
	printf("\n");
	//如果结构体成员包含结构体:
	printf("%d\n", sizeof(s5));  //输出结果:8
	printf("%d\n", sizeof(s6));  //输出结果:12
	printf("%d\n", sizeof(s7));  //输出结果:12
	return 0;
}

二.联合体的内存

规则:

1.大小必须足够容纳最宽的成员
2.大小能够被它所包含的所有的基本数据类型的大小整除

#include<stdio.h>

union MyUnion1{
	char s[9];     //  9 byte (char类型为 1 byte)
	int n;         //  4 byte
	double d;      //  8 byte
};                 // 16 byte

union MyUnion2 {
	char s[5];     //  5 byte
	int n;         //  4 byte
	double d;      //  8 byte
};                 //  8 byte
int main() {
	printf("%d\n", sizeof(MyUnion1));     // 结果:16
	printf("%d\n", sizeof(MyUnion2));     // 结果:8
}

三.枚举的内存

#include<stdio.h>

enum Enum {
	Enum1,      // (int) 4 byte
	Enum2,      // (int) 4 byte
	Enum3       // (int) 4 byte
}MyEnum;

int main() {
	printf("%d\n", sizeof(MyEnum));  // 结果:4
	printf("%d\n", sizeof(Enum1));   // 结果:4
	printf("%d\n", sizeof(Enum2));   // 结果:4
	printf("%d\n", sizeof(Enum3));   // 结果:4
	return 0;
}

关于枚举的解释大多数为:枚举皆为4字节;(例:如上情况)

——关于枚举内存的问题不必太深究,但是想探一探。

标准C语言描述没有明确规定枚举类型占用空间的大小,表示:“枚举类型的尺寸是以能够容纳最大枚举子值的整数的尺寸”,同时标准中也说明了: “枚举类型中的枚举子的值必须 能够 用一个int类型表述.”

#include<stdio.h>

enum Enum {
	Enum1 = 0x7f7f7f7f7f,    // (int类型最大值) (int) 4 byte
	Enum2,                   //               (int) 4 byte
	Enum3,                   //               (int) 4 byte
	Enum4 = 5,
	Enum5,
    Enum6 = 0x7f7f7f7f7f,    //(int类型最大值)
	Enum7
}MyEnum;

int main() {
	printf("%d\n", sizeof(MyEnum));  // 结果:8
	printf("%d\n", sizeof(Enum1));   // 结果:8
	printf("%d\n", sizeof(Enum2));   // 结果:8
	printf("%d\n", sizeof(Enum4));   // 结果:4
    printf("%d\n", sizeof(Enum5));   // 结果:4
    printf("%d\n", sizeof(Enum6));   // 结果:8
    printf("%d\n", sizeof(Enum7));   // 结果:8
	return 0;
}

当枚举子值超过 int 范围时 得到枚举字节占用为 8 byte

本以为是枚举定义为 long 类型尺寸,但是发现子值的输出并非正确数值输出,依旧溢出;

此处可能与 int 类型的大小有关:

(关于 int 类型)其大小为计算机的字长,与cpu寄存器位数相关

一般情况:32位计算机为4字节 64位计算机为8字节

但在 x64 计算机环境调试结果多数仍然为4字节可能和编译器等多方面条件有关。

搜索资料中发现这样一篇文章:https://blog.csdn.net/HES_C/article/details/88668276

按照c语言描述可以实现,但本人未能实现。查询整理得到另一些合理解释:

具体内容如下:

1.转载:https://embedded.fm/blog/2016/6/28/how-big-is-an-enum

2.来自知乎留言:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1D43Ryqp-1644332606219)(3-1.png)]

计算机为8字节

但在 x64 计算机环境调试结果多数仍然为4字节可能和编译器等多方面条件有关。

搜索资料中发现这样一篇文章:https://blog.csdn.net/HES_C/article/details/88668276

按照c语言描述可以实现,但本人未能实现。查询整理得到另一些合理解释:

具体内容如下:

1.转载:https://embedded.fm/blog/2016/6/28/how-big-is-an-enum

2.来自知乎留言:

在这里插入图片描述

enum本身并不以变量的方式存储到内存当中,但是将enum本身作为变量(包括指定具体是哪个枚举值),因为这个变量包含了枚举类型中的一部分值,所以会分配空间,这个具体值的大小,应该和机器、枚举值指定值有关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MuShan-bit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值