0
点赞
收藏
分享

微信扫一扫

C语言之自定义类型

一只1994 2022-04-01 阅读 101
c语言

目录

1.结构体

 1.1 结构体的基础知识

 1.2结构的声明

1.3 特殊的声明(匿名)

 1.4结构的自引用

 1.5结构体变量的定义和初始化 

 1.6 结构体内存对齐(非常重要)

 1.7修改默认对齐数

1.8 结构体传参 

2.位段

2.1 什么是位段

2.2位段的内存分配 

2.3位段的跨平台问题 

3.枚举 

3.1 枚举类型的定义

 3.2枚举的优点

3.3枚举的使用 

3.4 枚举大小的计算

4.联合(共用体) 

4.1联合类型的定义

4.2联合的特点

4.3用联合来判断大小端

 4.4 联合大小的计算

这里特别注意:数组的对齐数是看类型的大小的


1.结构体

 1.1 结构体的基础知识

 1.2结构的声明

eg:描述一个学生

1.3 特殊的声明(匿名)

在声明结构的时候,可以不完全的声明。

//匿名结构体类型
struct
{
 int a;
 char b;
 float c; 
}x;

 声明的时候省略掉了结构体标签(tag)

上述代码,ps = &sa是否合法

警告 :编译器会把上面的两个声明当成完全不同的两个类型

所以是非法的。

 1.4结构的自引用

举例: 

struct Note
{
	int data;
	struct Note* next;
};

注意:匿名结构体类型不可以自引用 

 1.5结构体变量的定义和初始化 

 1.6 结构体内存对齐(非常重要)

结构体的对齐规律

 下面是3道关于计算结构体大小的例题,让我们一起来看下吧


//eg1 :求s1大小
struct s1   //12
{
	char c1;//1
	int i;//4
	char c2;//1
};

 

 

//eg2 :求s2大小
struct s2//8
{
	char c1;
	char c2;
	int i;
};

 

 

//eg3 嵌套结构体类型 (求s4大小)
struct s3//16
{
	double d;//8
	char c;//1
	int i;//4
};

struct s4 //32
{
	char c1;//1
	struct s3 s3;//16
	double d;//8
};

 

为什么存在内存对齐 ?

在设计结构体的时候,满足对齐,节省空间的方法是

让占用空间小的成员尽量集中在一起。

struct S1
{
 char c1;
 int i;
 char c2;
};
struct S2
{
 char c1;
 char c2;
 int i;
};

 1.7修改默认对齐数

#pragma 这个预处理指令,可以帮助我们改变默认对齐数。

#pragma pack(1) //设置默认对齐数为1
struct s1 //6
{
	char a;
	int i;
	char b;
};
#pragma pack() //取消设置的默认对齐数
int main()
{
    //不修改对齐数的结果为12
	printf("%d\n", sizeof(struct s1));//结果为6
}

1.8 结构体传参 

咱们直接上代码

#include<stdio.h>
struct S 
{
 int data[1000];
 int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
 {
 printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps) 
{
 printf("%d\n", ps->num);
}
int main()
{
 print1(s);  //传结构体
 print2(&s); //传地址
 return 0; 
}

2.位段

2.1 什么是位段

位段的声明和结构是类似的,有两个不同:

struct a
{
	int _a : 2;//这里的2代表2个比特位(1字节=8比特位)
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	printf("%d\n", sizeof(struct a));//位段a的大小为8
}

2.2位段的内存分配 

一个例子

struct S 
{
 char a:3;
 char b:4;
 char c:5;
 char d:4;
};
struct S s = {0};
s.a = 10; 
s.b = 12;
s.c = 3; 
s.d = 4;

上面代码的空间是如何开辟的呢

2.3位段的跨平台问题 

3.枚举 

3.1 枚举类型的定义

拿星期举例:

#include<stdio.h>
enum Day//相当于等差数列 ,d=1
{
	Mon,
	Tues,
	Wed,
	Thir,
	Fri
};

int main()
{
	printf("%d %d %d %d %d\n", Mon, Tues, Wed, Thir, Fri);
	return 0;
}

当然在定义的时候也可以赋初值,例如:

#include<stdio.h>
enum Color//颜色
{
    RED = 1,//定义+赋值
    GREEN,
    BLUE=4
};
int main()
{
    printf("%d %d %d", RED, GREEN, BLUE);
    return 0;
}

运行截图

 3.2枚举的优点

3.3枚举的使用 

enum Color
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;               //error  要拿{}内的枚举常量来赋值

3.4 枚举大小的计算

#include<stdio.h>
enum Color
{
    RED = 1,
    GREEN,
    BLUE=4
};
int main()
{
    enum Color c = RED;
    printf("%d\n",sizeof(enum Color));//4
    printf("%d\n", sizeof(c));//4
    return 0;
}

运行截图

4.联合(共用体) 

4.1联合类型的定义

#include<stdio.h>
union Un
{
	int i;
	char c;
};

int main()
{
	union Un un;
    printf("%d\n",sizeof(un));
	printf("%d\n", &(un.i));
	printf("%d\n", &(un.c));
	un.i = 0x1122;
	un.c = 0x44;
	printf("%x\n", un.i);
}

 运行截图

 由此可见:联合的大小至少为最大成员的大小,成员共用同一块空间(地址相同)

4.2联合的特点

4.3用联合来判断大小端

方法一:一般方法

#include<stdio.h>
int cheak()
{
	int a = 1;
	return (*(char*)&a);
}
int main()
{
	int ret = cheak_sys();
	if (1 == ret)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

方法二:联合

#include<stdio.h>
int cheak_sys()
{
	union Un//这里联合体只能使用一次(可以把Un删掉,改为匿名的(和结构体用法一样))--好处是万一与后面的变量重名时不会冲突
	{
		char c;
		int i;
	}u;
	u.i = 1;
	return u.c;
}
int main()
{
	int ret = cheak_sys();
	if (1 == ret)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

 4.4 联合大小的计算

#include<stdio.h>
union Un1
{
	char c[5];//5
	int i;//4->最大对齐数
};
union Un2
{
	short c[7];//14 
	int i;//4->最大对齐数
};
int main()
{
	printf("%d\n", sizeof(union Un1));//8
	printf("%d\n", sizeof(union Un2));//16
	return 0;
}

这里特别注意数组的对齐数是看类型的大小的

 

 感谢观看!

 

举报

相关推荐

0 条评论