C语言自定义类型详解(保姆级教学)

简介: C语言自定义类型详解(保姆级教学)

什么是自定义类型?

在C语言中,我们可以使用结构体(Struct),枚举(Enum),联合体(Union)来创建自定义的类型。


1.结构体


1.1结构体的介绍


结构体(Struct):结构体是一种用户定义的数据类型,用于将不同类型的数据组合在一起,形成一个新的复合类型。结构体由一组成员(member)组成,每个成员可以是不同的数据类型,如整型、字符型、浮点型、指针等。结构体的定义使用 struct 关键字,然后指定结构体的名称以及成员列表。


1.2结构体的声明


struct student
{
  char name[20];
  int age;
  char sex[5];
  char id[20]
};


在上述代码中,我们定义了一个名为student的结构体,包含了一个整形类型和三个字符类型的数组。


1.3特殊声明(匿名结构体类型)


struct
{
  int a;
  float b;
  float c;
}x;


在上述代码中,省略了结构体的标签——这就是匿名结构体类型。


1.4结构体自引用


我们可以在结构体中包含一个结构体,如果包含的这个结构体是该结构体本身的结构体指针即为结构体的自引用。

struct student
{
  int age;
  char name[20];
  struct student* s1;
};


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


struct student
{
  int age;
  char name[20];
}s1,s2;//在声明结构体类型时定义变量s1,s2
struct student s3;//定义结构体变量s3
struct point
{
  int x;
  int y;
}p1={1,1};//结构体嵌套初始化
struct point p2 = { 1,2 };//初始化


1.6结构体内存对齐


结构体内存对齐是用来计算结构体的大小的

如何计算?

首先得掌握结构体的对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

VS中默认的值为8

Linux中没有默认对齐数,对齐数就是成员自身的大小

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整

体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。


实例:

struct S1
{
  char c1;
  int i;
  char c2;
};
int main()
{
  printf("%d \n", sizeof(struct S1));
  return 0;
}


baa707433a7f4505b37286c7ba97b54e.png

63324d0978bc494d890e077dd9dabd12.png

为什么存在内存对齐?

大部分的参考资料都是如是说的:

1. 平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特

定类型的数据,否则抛出硬件异常。

2. 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访

问。

总体来说:

结构体的内存对齐是拿空间来换取时间的做法


1.7修改默认对其数


#pragma pack(1)//设置默认对齐数为1
struct S3
{
  double d;
  char c;
  int i;
};
struct S4
{
  char c1;
  struct S3 s3;
  double d;
};
#pragma pack ()//取消设置默认对齐数,还原为默认


2.位段


2.1什么是位段


位段(Bitfields)是C语言中一种用于定义结构体成员的技术,它允许我们对结构体中的数据进行位级别的控制。


位段的目的是在结构体成员中存储各个字段(或位)的数据,并利用较少的内存空间。通常,在处理一些较小范围的整数值时,使用完整的字节或更大的数据类型可能会浪费内存。


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


1.位段的成员必须是 int、unsigned int 或signed int 。

2.位段的成员名后边有一个冒号和一个数字


比如:

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


student就是一个位段类型。那student的大小呢?

53ecb45a04da400fa7c287f755238c63.png


2.2位段的内存分配


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

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

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


实例:

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;


005b5378dc0242628ffbf333305d2140.png


3.枚举


3.1枚举的定义


enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
enum Color//颜色
{
RED,
GREEN,
BLUE
};

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。

{}中的内容是枚举类型的可能取值,也叫 枚举常量 。

这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

例如:

enum Color//颜色
{
RED=1,
GREEN=2,
BLUE=4
};


3.2枚举的优点


为什么使用枚举?

我们可以使用 #define 定义常量,为什么非要使用枚举?

枚举的优点:

1. 增加代码的可读性和可维护性

2. 和#define定义的标识符比较枚举有类型检查,更加严谨。

3. 便于调试

4. 使用方便,一次可以定义多个常量


4.联合体(共用体)


联合体是一种特殊的数据类型,允许在相同的内存位置存储不同类型的数据。与结构体不同的是,联合体中的各个成员共享相同的内存空间。


4.1联合体类型的定义


//联合体类型的声明
union Un
{
  char c;
  int i;
};
int main()
{
  //联合体变量的定义
  union Un un;
  //计算联合体变量的大小
  printf("%d\n", sizeof(un));
  //打印结果为4
}


4.2联合体的特点


联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联

合至少得有能力保存最大的那个成员)。

union Un
{
  int i;
  char c;
};
int main()
{
  union Un un;
  printf("%d \n", &(un.i));
  printf("%d \n", &(un.c));
  un.i = 1;
  un.c = 2;
  printf("%d \n", un.i);
  return 0;
}


ab6b659b6f764498ae7b0f2c711b0b1b.png


实例:判断当前机器的大小端?

int Pd()
{
  union
  {
    int i;
    char c;
  }un = { .i = 1 };
  return un.c;
}
int main()
{
  int ret = Pd();
  if (ret == 1)
  {
    printf("小端\n");
  }
  else
  {
    printf("大端\n");
  }
  return 0;
}


0109baec62d746a8891c50de7a0797a9.png


4.3联合体大小的计算


联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

相关文章
|
20天前
|
安全 编译器 Linux
【c语言】轻松拿捏自定义类型
本文介绍了C语言中的三种自定义类型:结构体、联合体和枚举类型。结构体可以包含多个不同类型的成员,支持自引用和内存对齐。联合体的所有成员共享同一块内存,适用于判断机器的大小端。枚举类型用于列举固定值,增加代码的可读性和安全性。文中详细讲解了每种类型的声明、特点和使用方法,并提供了示例代码。
17 3
|
1月前
|
C语言 C++
保姆式教学C语言——数组
保姆式教学C语言——数组
16 0
保姆式教学C语言——数组
|
1月前
|
存储 编译器 Linux
C语言——自定义类型
C语言——自定义类型
|
29天前
|
C语言
保姆级教学 - C语言 之 动态内存管理
保姆级教学 - C语言 之 动态内存管理
17 0
|
1月前
|
机器学习/深度学习 编译器 C语言
C语言刷题(中)(保姆式详解)
C语言刷题(中)(保姆式详解)
13 0
|
1月前
|
机器学习/深度学习 C语言
C语言必刷题上(保姆式详解)
C语言必刷题上(保姆式详解)
13 0
|
1月前
|
存储 编译器 C语言
【C语言】自定义类型:联合与枚举的简明概述
【C语言】自定义类型:联合与枚举的简明概述
|
3月前
|
存储 编译器 C语言
【C语言篇】自定义类型:联合体和枚举详细介绍
像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
45 1
|
3月前
|
存储 安全 编译器
C语言自定义类型
C语言自定义类型
33 10
|
5月前
|
编译器 测试技术 C语言
【C语言】:自定义类型:结构体的使用及其内存对齐
【C语言】:自定义类型:结构体的使用及其内存对齐
67 7