C语言结构体-位段-枚举类型enum-联合体union详解

目录

 一、结构体声明与自引用

二、结构体内存对齐

为什么要内存对齐?

计算结构体的大小

offsetof 宏的实现

三、位段

四、枚举类型enum

五、联合体union 

联合体应用


 一、结构体声明与自引用

struct
{//没有标签,匿名结构体类型,属于不完全声明
    int a;
    char b;
    float c;
}x;//这里x是全局变量
struct
{
    int a;
    char b;
    float c;
}a[20], * p;//这里是结构体指针

一个问题:

p=&x,合法吗?

答:不合法,编译器会认为这是两个结构体,所以这两边是驴头不对马嘴

结构体自引用

struct Node
{
    int data;
    struct Node next;
};
//可行否?
如果可以,那sizeof(struct Node)是多少?

答:不行,int-4 下面又是4,死循环套了,所以要用指针,指向同类型节点的下一个地方,而指针类型大小是4/8。所以要这样写:

struct Node

{

     int data;

     struct Node* next;

};

tips:

typedef struct
{
    int data;
    Node* next;
}Node;
//这样写代码,可行否?是先有struct还是先有Node呢
//解决方案:先有struct
typedef struct Node
{
    int data;
    struct Node* next;
}Node;

tips:

结构体传参最好传地址,这样可以控制实参的改变是否影响形参,如果传结构体会导致实参的改变不能影响形参,因为是相当于开辟了2块存储空间。空间开销大,性能低。

二、结构体内存对齐

为什么要内存对齐?

1.某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.为了便于访问,不对齐可能会遇到一个in提取2次的情况。

计算结构体的大小

1.int有4个字节,VS默认对齐数是8,选最小的4,而且它要对齐在最小倍数上,

2.char有一个字节,倍数是1,第一个成员在与结构体变量偏移量为0的地址处。

3.最后结果9个空间,还要取它最大对齐数(每个成员变量都有一个对齐数)的最小整数倍。最大对齐数这里是4。

例子1:

C语言结构体-位段-枚举类型enum-联合体union详解_第1张图片

例子2:

C语言结构体-位段-枚举类型enum-联合体union详解_第2张图片

由于这个特点,可以自己想想怎么放会比较节约空间。

还可以通过修改默认对齐数:

#pragma pack(1)//设置默认对齐数为1
struct S2
{

};
#pragma pack()//取消设置,还原VS默认对齐数
 

 例子3:

s5进行了结构体嵌套,这里的结果是16的整数倍还是8的整数倍?

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

答:是8

C语言结构体-位段-枚举类型enum-联合体union详解_第3张图片

offsetof 宏的实现

offsetof可以看结构体成员变量相对起始位置(首地址)的偏移量,

程序结果为0 4 8

#include
#include
	struct stu
	{
		int a;
		char b;
		double c;
	};
 
#define OFFSETOF(struct_type,mem_name) (size_t)&(((struct_type*)0)->mem_name)
 
int main()
 {
 
	printf("%d\n", OFFSETOF(struct stu, a));
	printf("%d\n", OFFSETOF(struct stu, b));
	printf("%d\n", OFFSETOF(struct stu, c));
 
	return 0;
 }

三、位段

struct A
{
    int _a : 2;
    int _b : 5;
    int _c : 10;
    int _d : 30;
};

位段成员必须是 int unsigned 或signed int

位段的大小要看内存分配

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型

2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

例:1:

C语言结构体-位段-枚举类型enum-联合体union详解_第4张图片

 说明:

大小端是字节序,一个字节内部顺序是与大小端无关的

跟结构相比,位段可以达到同样的效果(因为它可以分配空间大小),但是可以很好的节省空间,但是有跨平台的问题存在。

例子2:

 C语言结构体-位段-枚举类型enum-联合体union详解_第5张图片

16位-----int-----2个byte-----16bit

32位-----int-----4个byte-----32bit

四、枚举类型enum

C语言结构体-位段-枚举类型enum-联合体union详解_第6张图片

 enum优势:

用#define RED 1也行,但是它会在预编译阶段将RED进行转化为1,在调试时我看到1不会想到RED,不便于调试,enum可以解决这个问题。C语言结构体-位段-枚举类型enum-联合体union详解_第7张图片

五、联合体union 

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

//联合类型的声明
union Un
{
    char c;
    int i;
};
//联合变量的定义
union Un un;
//计算连个变量的大小
printf("%d\n", sizeof(un));

联合体应用

判断大小端存储:

C语言结构体-位段-枚举类型enum-联合体union详解_第8张图片

 C语言结构体-位段-枚举类型enum-联合体union详解_第9张图片

 C语言结构体-位段-枚举类型enum-联合体union详解_第10张图片

 结果是12,不是10,4,因为short对齐数是2,int是4,要满足第2点,最小4的倍数是12.

1. 联合的大小至少是最大成员的大小。

2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。C语言结构体-位段-枚举类型enum-联合体union详解_第11张图片

 最后的打印结果表明:

union共有一块内存空间,改变一个会影响另外一个。

总结

如有错误,希望各位父老乡亲及时指正。

你可能感兴趣的:(开发语言,c语言,青少年编程)