当前位置:   article > 正文

【C】自定义数据类型_c自定义数据类型

c自定义数据类型

目录

一、结构体

        结构体声明

        特殊声明

        结构体创建变量

        结构体自引用

        结构体重定义

        结构体变量初始化

        结构体内存对齐

        offsetof

        修改最大对齐数

        结构体传参

二、位段

        位段的内存分配

        位段的跨平台问题

        位段的应用

三、联合

        联合内成员的空间占用

        联合的大小计算

四、枚举

        枚举内成员值

        枚举的使用

        枚举相对于 define 的优点


一、结构体

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

        结构体声明

  1. //创建「人」的数据类型
  2. struct People //「struct People」为数据类型名,其中「struct」固定,「People」自定义
  3. {
  4. char name[10];//姓名
  5. int age;//年龄
  6. };

        特殊声明(不加结构体标签)

  1. struct
  2. {
  3. char name[10];
  4. int age;
  5. };

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

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

        结构体创建变量

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

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

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

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

        结构体自引用

错误:

  1. struct People
  2. {
  3. char name[10];
  4. int age;
  5. struct People p;
  6. };

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

正确:

  1. struct People
  2. {
  3. char name[10];
  4. int age;
  5. struct People *p;
  6. };

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

特殊声明不可进行自引用

 

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

        结构体重定义

  1. typedef struct People
  2. {
  3. char name[10];
  4. int age;
  5. }P;
  6. //将「struct People」重定义为「P」

        结构体变量初始化

 (1)一般初始化

  1. struct People
  2. {
  3. char name[10];
  4. int age;
  5. };
  6. struct People p = { "张三",18 };

  1. struct People
  2. {
  3. char name[10];
  4. int age;
  5. }p = { "张三",18 };

(2)嵌套初始化

  1. struct A
  2. {
  3. int b;
  4. };
  5. struct People
  6. {
  7. char name[10];
  8. int age;
  9. struct A a;
  10. };
  11. struct People p = { "张三",18 ,{0} };
  12. //因为p中的a是结构体,所以也需要使用{}

        结构体内存对齐

 用空间换取时间

作用:

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

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

 内存对齐规则:

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

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

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

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

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

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

例 1:

  1. struct X
  2. {
  3. char c1;
  4. int i;
  5. char c2;
  6. }x;
  7. struct Y
  8. {
  9. char c1;
  10. char c2;
  11. int i;
  12. }y;
  13. int main()
  14. {
  15. sizeof(x);
  16. sizeof(y);
  17. return 0;
  18. }

答案:12、8

  例 2:

  1. struct X
  2. {
  3. char c1;
  4. int i;
  5. char c2;
  6. };
  7. struct Y
  8. {
  9. char c1;
  10. char c2;
  11. struct X x;
  12. char c3;
  13. }y;
  14. int main()
  15. {
  16. sizeof(y);
  17. return 0;
  18. }

答案:20

        offsetof

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

例:

  1. struct X
  2. {
  3. char c1;
  4. int i;
  5. char c2;
  6. }x;
  7. struct Y
  8. {
  9. char c1;
  10. char c2;
  11. struct X x;
  12. char c3;
  13. }y;
  14. int main()
  15. {
  16. printf("%d\n", sizeof(y));
  17. printf("%d\n", offsetof(struct Y, c1));
  18. printf("%d\n", offsetof(struct Y, c2));
  19. printf("%d\n", offsetof(struct Y, x));
  20. printf("%d\n", offsetof(struct Y, c3));
  21. return 0;
  22. }

        修改最大对齐数

 例:

  1. #pragma pack(1)//将最大对齐数改为1
  2. struct X
  3. {
  4. char c1;
  5. int i;
  6. char c2;
  7. }x;
  8. #pragma pack()//将最大对齐数改回默认值

        结构体传参

(1)值传递

  1. struct A
  2. {
  3. int i;
  4. };
  5. void print(struct A a)
  6. {
  7. printf("%d", a.i);
  8. }
  9. int main()
  10. {
  11. struct A a = { 1 };
  12. print(a);
  13. return 0;
  14. }

(2)地址传递

  1. struct A
  2. {
  3. int i;
  4. };
  5. void print(struct A* a)
  6. {
  7. printf("%d", a->i);
  8. }
  9. int main()
  10. {
  11. struct A a = { 1 };
  12. print(&a);
  13. return 0;
  14. }

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

二、位段

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

 例:

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

        位段的内存分配

 (1)位段只能是整型

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

例:

  1. struct S
  2. {
  3. int a : 3;
  4. int b : 4;
  5. int c : 5;
  6. int d : 4;
  7. };
  8. int main()
  9. {
  10. struct S s = { 0 };
  11. s.a = 10;
  12. s.b = 12;
  13. s.c = 3;
  14. s.d = 4;
  15. return 0;
  16. }

        位段的跨平台问题

位段不可跨平台

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

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

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

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

        位段的应用

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

三、联合

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

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

        联合内成员的空间占用

 例:

  1. union U
  2. {
  3. int i;
  4. char c;
  5. }u;
  6. int main()
  7. {
  8. printf("%d\n", &(u.i));
  9. printf("%d\n", &(u.c));//(1)
  10. u.i = 0x11223344;
  11. u.c = 0x55;
  12. printf("%x\n", u.i);//(2)(小端环境下)
  13. return 0;
  14. }

结果:

(1)2 个地址相同

(2)44332200

        联合的大小计算

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

例 1:

  1. union U
  2. {
  3. char c[5];
  4. int i;
  5. }u;
  6. int main()
  7. {
  8. printf("%d\n", sizeof(u));
  9. return 0;
  10. }

答案:8

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

例 2:

  1. union U
  2. {
  3. short c[7];
  4. int i;
  5. }u;
  6. int main()
  7. {
  8. printf("%d\n", sizeof(u));
  9. return 0;
  10. }

答案:16

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

四、枚举

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

例:

  1. enum Colour//颜色
  2. {
  3. BLUE,
  4. GREEN,
  5. RED
  6. };
  7. enum Sex//性别
  8. {
  9. MAN,
  10. WOMAN
  11. };

        枚举内成员值

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

例 1:

  1. enum Colour
  2. {
  3. BLUE,
  4. GREEN,
  5. RED
  6. };
  7. int main()
  8. {
  9. printf("%d", BLUE);
  10. printf("%d", GREEN);
  11. printf("%d", RED);
  12. return 0;
  13. }

结果:0、1、2

例 2:

  1. enum Colour
  2. {
  3. BLUE=1,
  4. GREEN,
  5. RED=5
  6. };
  7. int main()
  8. {
  9. printf("%d", BLUE);
  10. printf("%d", GREEN);
  11. printf("%d", RED);
  12. return 0;
  13. }

结果:1、2、5

        枚举的使用

例:

  1. enum Colour
  2. {
  3. BLUE=,
  4. GREEN,
  5. RED=
  6. };
  7. int main()
  8. {
  9. enum Colour c;
  10. c = GREEN;
  11. return 0;
  12. }

错误用法:

  1. enum Colour
  2. {
  3. BLUE,
  4. GREEN,
  5. RED
  6. };
  7. int main()
  8. {
  9. enum Colour c;
  10. c = 1;
  11. return 0;
  12. }

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

        枚举相对于 define 的优点

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

(2)有类型,更严谨

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

(4)增加代码可读性

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/518909
推荐阅读
相关标签
  

闽ICP备14008679号