栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C】自定义数据类型

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【C】自定义数据类型

目录

一、结构体

        结构体声明

        特殊声明

        结构体创建变量

        结构体自引用

        结构体重定义

        结构体变量初始化

        结构体内存对齐

        offsetof

        修改最大对齐数

        结构体传参

二、位段

        位段的内存分配

        位段的跨平台问题

        位段的应用

三、联合

        联合内成员的空间占用

        联合的大小计算

四、枚举

        枚举内成员值

        枚举的使用

        枚举相对于 define 的优点


一、结构体

结构体:由变量组成的数据类型。

        结构体声明
//创建「人」的数据类型
struct People //「struct People」为数据类型名,其中「struct」固定,「People」自定义
{
	char name[10];//姓名
	int age;//年龄
};

        特殊声明(不加结构体标签)
struct
{
	char name[10];
	int age;
};

当用特殊声明创建多个结构体时,编译器将全部视为不同类型。

例:用特殊声明创建 2 个一样的结构体,创建变量后进行赋值。

        结构体创建变量

  (1)主函数内创建变量(局部变量)

struct People p1, p2;
struct People* p1, *p2;//指针变量

(2)声明结构体时创建变量(全局变量)

struct People
{
	char name[10];
	int age;
}p1,p2;//创建「p1」「p2」两个「struct People」类型的变量
struct People
{
	char name[10];
	int age;
}*p1,*p2;//创建「p1」「p2」两个「struct People」类型的指针变量

        结构体自引用

错误:

struct People
{
	char name[10];
	int age;
	struct People p;
};

当 People 中创建了 p 时,p 里面还会包含一个 p,不断循环下去,导致计算不出占用内存大小,所以编译器报错。

正确:

struct People
{
	char name[10];
	int age;
	struct People *p;
};

当用指针的方式进行自引用,只需提供一个固定的指针类型大小就可以了。

特殊声明不可进行自引用

 

 将 struct 进行重定义之后,编译器还是会将创建出来的不同变量视为不同类型。

        结构体重定义
typedef struct People
{
    char name[10];
    int age;
}P;
//将「struct People」重定义为「P」

        结构体变量初始化

 (1)一般初始化

struct People
{
	char name[10];
	int age;
};

struct People p = { "张三",18 };

或

struct People
{
	char name[10];
	int age;
}p = { "张三",18 };

(2)嵌套初始化

struct A
{
	int b;
};

struct People
{
	char name[10];
	int age;
	struct A a;
};

struct People p = { "张三",18 ,{0} };
//因为p中的a是结构体,所以也需要使用{}

        结构体内存对齐

 用空间换取时间

作用:

(1)提高可移植性,某些平台只能在特定地址取出特定数据类型。

(2)提高性能:有时访问未对齐内存可能要比对齐内存多访问一次,因为内存对齐后,系统就知道从哪开始访问获取该数据。

 内存对齐规则:

(1)所有成员须对其到对齐数的整数倍偏移量处

(2)结构体总大小为成员最大对齐数的整数倍

(3)数组或嵌套结构体的偏移量为自身内变量的最大偏移量

对齐数:该成员占用字节数,VS 下最大不超过8

偏移量:内存单位与起始位置的距离

集中占用空间小的成员可以节约空间

例 1:

struct X
{
	char c1;
	int i;
	char c2;
}x;

struct Y
{
	char c1;
	char c2;
	int i;
}y;

int main()
{
	sizeof(x);
	sizeof(y);

	return 0;
}

答案:12、8

  例 2:

struct X
{
	char c1;
	int i;
	char c2;
};

struct Y
{
	char c1;
	char c2;
	struct X x;
    char c3;
}y;

int main()
{
	sizeof(y);

	return 0;
}

答案:20

        offsetof

 使用 offsetof 可查看结构体类型中变量所在偏移处,需包含头文件 < stddef.h>

例:

struct X
{
	char c1;
	int i;
	char c2;
}x;

struct Y
{
	char c1;
	char c2;
	struct X x;
	char c3;
}y;

int main()
{
	printf("%dn", sizeof(y));
	printf("%dn", offsetof(struct Y, c1));
	printf("%dn", offsetof(struct Y, c2));
	printf("%dn", offsetof(struct Y, x));
	printf("%dn", offsetof(struct Y, c3));

	return 0;
}

        修改最大对齐数

 例:

#pragma pack(1)//将最大对齐数改为1
struct X
{
	char c1;
	int i;
	char c2;
}x;
#pragma pack()//将最大对齐数改回默认值

        结构体传参

(1)值传递

struct A
{
	int i;
};

void print(struct A a)
{
	printf("%d", a.i);
}

int main()
{
	struct A a = { 1 };
	print(a);

	return 0;
}

(2)地址传递

struct A
{
	int i;
};

void print(struct A* a)
{
	printf("%d", a->i);
}

int main()
{
    struct A a = { 1 };
	print(&a);

	return 0;
}

函数传参时需要进行压栈,如果参数过大会导致不必要的时间、空间消耗,所以结构体传参时,地址传递优于值传递。

二、位段

声明结构体时,在其中的成员后加上为该成员分配的内存(以位为单位),该结构体成员称为位段。

 例:

struct S
{
	int a : 3;//给a分配3个比特位
	int b : 4;//给b分配4个比特位
	int c : 5;//给c分配5个比特位
	int d : 4;//给d分配4个比特位
};

        位段的内存分配

 (1)位段只能是整型

(2)位段以不同整型大小按需开辟空间

例:

struct S
{
	int a : 3;
	int b : 4;
	int c : 5;
	int d : 4;
};

int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;

	return 0;
}

        位段的跨平台问题

位段不可跨平台

(1)int 类型被当做有符号或无符号不确定

(2)位数不确定(16 为机器下 int 为 2 字节)

(3)内存从左向右分配或相反,尚未确定

(4)开辟新空间时,旧空间利用或舍弃未确定

        位段的应用

位段应用在数据报文中,因为报文中每个字段所需空间极小。

三、联合

所有成员共用同一片空间的数据类型叫联合。

联合的声明、变量创建同结构体一样,只需将结构体中的「struct」替换为「union」

        联合内成员的空间占用

 例:

union U
{
	int i;
	char c;
}u;


int main()
{
	printf("%dn", &(u.i));
	printf("%dn", &(u.c));//(1)
	
	u.i = 0x11223344;
	u.c = 0x55;
	printf("%xn", u.i);//(2)(小端环境下)

	return 0;
}

结果:

(1)2 个地址相同

(2)44332200

        联合的大小计算

联合的大小为最大成员大小且为成员内最大对齐数的倍数

例 1:

union U
{
	char c[5];
	int i;
}u;
int main()
{
	printf("%dn", sizeof(u));
	return 0;
}

答案:8

最大成员大小为 5(char [5]),最大对齐数为 4(int)

例 2:

union U
{
	short c[7];
	int i;
}u;
int main()
{
	printf("%dn", sizeof(u));
	return 0;
}

答案:16

最大成员大小为 5(short [7]),最大对齐数为 4(int)

四、枚举

 枚举的作用类似 define,但是枚举将定义的常量有类型且以类型分组。

例:

enum Colour//颜色
{
	BLUE,
	GREEN,
	RED
};

enum Sex//性别
{
	MAN,
	WOMAN
};

        枚举内成员值

枚举内成员的值默认从 0 开始递增,可自定义。

例 1:

enum Colour
{
	BLUE,
	GREEN,
	RED
};

int main()
{
	printf("%d", BLUE);
	printf("%d", GREEN);
	printf("%d", RED);
	return 0;
}

结果:0、1、2

例 2:

enum Colour
{
	BLUE=1,
	GREEN,
	RED=5
};

int main()
{
	printf("%d", BLUE);
	printf("%d", GREEN);
	printf("%d", RED);
	return 0;
}

结果:1、2、5

        枚举的使用

例:

enum Colour
{
	BLUE=,
	GREEN,
	RED=
};

int main()
{
	enum Colour c;
	c = GREEN;
	return 0;
}

错误用法:

enum Colour
{
	BLUE,
	GREEN,
	RED
};

int main()
{
	enum Colour c;
	c = 1;
	return 0;
}

因为 1 是整型,而 c 是 enum Colour 类型,不同类型不能进行赋值。

        枚举相对于 define 的优点

(1)可一次性定义多个常量

(2)有类型,更严谨

(3)便于调试,程序执行前的预编译会进行宏替换,从而不能观察到 define 定义的值

(4)增加代码可读性

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1011103.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号