【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)

简介: 【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)

一、结构体


  结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

  1. 结构体声明
    结构体在声明是可以不完全声明。


struct Book {
  char name[20];
  int price;
  char id[12];
}b4,b5,b6;//b4,b5,b6是全局的
//不完全声明,匿名结构体类型
struct {
  char c;
  int i;
  char ch;
  double d;
} s;
int main() {
  //b1,b2,b3是局部的
  struct Book b1;
  struct Book b2;
  struct Book b3;
  return 0;
}


  1. 结构体自引用
    结构体自引用,结构体可以包含结构体。
struct Node {
  int d;
  struct Node* next;
};
int main() {
  struct Node n;
  return 0;
}



3.结构体内存对齐

3.1 第一个成员在与结构体偏移量为0的地址处存放;

3.2 其他成员变量都放在某一个对齐数的整数倍的地址处;

 对齐数是编译器默认的对齐数与该成员字节的大小中较小的那一个,vs中默认的值为8;

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

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

struct S {
  char c;
  int i;
};
struct B {
  double d;
  struct S s;
  char c;
};
int main() {
  printf("%d\n", sizeof(struct S));
  printf("%d\n", sizeof(struct B));
  struct S s1 = {'x', 20};
  struct B sb = { 3.14, {'x', 20}, 'q' };
  //.针对结构体变量
  //->针对结构体指针
  printf("%lf %c %d %c\n",sb.d, sb.s.c, sb.s.i, sb.c);
  return 0;
}

a052268ba855445488fa93d2b0bc6d20.png7f08a1869e364c618115fa8d2caabdb2.png



4.为什么存在对齐数

4.1 平台原因(移植原因):

  不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

4.2性能原因:
  数据结构(尤其是栈)应该尽可能地在自然边界上对齐;
  原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
结构体的内存对齐是拿空间来换取时间的做法。


5.设置默认对齐数


#pragma pack(2)
struct S {
  char c1;
  int i;
  char c2;
};
#pragma pack()
int  main() {
  struct S s = { 0 };
  printf("%d\n", sizeof(s));
  return 0;
}
  1. 结构体传参
      函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销;
      如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降;
      结构体传参的时候,要传结构体的地址。
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; 
 }


二、位段


1.位段声明
1.1位段的成员必须是 int、unsigned int 或signed int;
1.2位段的成员名后边有一个冒号和一个数字。

2.位段的内存分配

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

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

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

3.跨平台问题

3.1int位段被当成有符号数还是无符号数是不确定的;

3.2位段中最大位的数目不能确定(16位机器最大16,32位机器最大32,写成27,在16位机

器会出问题);

3.3位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义;

3.4当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是

舍弃剩余的位还是利用,这是不确定的。

struct A {
  // 4字节 - 32bit
  int _a : 2;// _a成员占2个bit位
  int _b : 5;// _b成员占5个bit位
  int _c : 10;// _c成员占10个bit位
  //15
  // 4个字节 - 32bit
  int _d : 30;// _d成员占30个bit位
};
int main() {
  printf("%d\n", sizeof(struct A));
  return 0;
}


三、枚举


  枚举就是把可能的取值一一列举。

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

  这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。

enum Color {
  RED,//0
  CREEN,//1
  BLUE//2
};
int main() {
  enum Color c = BLUE;
  printf("%d\n", sizeof(c));
  printf("%d\n", RED);
  printf("%d\n", CREEN);
  printf("%d\n", BLUE);
  return 0;
}

为什么使用枚举:

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

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

  3.防止了命名污染(封装);

  4.便于调试;

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


四、联合(共用体


联合也是一种特殊的自定义类型;

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

 联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小,因为联合至少得有能力保存最大的那个成员;

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

int check_sys() {
  union U {
    char c;
    int i;
  }u;
  u.i = 1;
  return u.c;
}
int main() {
  int ret = check_sys();
  if (1 == ret)
    printf("小端\n");
  else
    printf("大端\n");
  return 0;
}
union Un1 {
  char c[5];
  int i;
};
union Un2 {
  short c[7];
  int i;
};
//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));


目录
相关文章
|
4月前
|
Linux C语言 C++
自定义类型——结构体、枚举和联合
自定义类型——结构体、枚举和联合
|
7月前
|
存储 编译器 Linux
自定义数据类型:结构体+枚举+联合
自定义数据类型:结构体+枚举+联合
|
存储 编译器 C语言
自定义数据类型:结构体,枚举,联合
自定义数据类型:结构体,枚举,联合
|
存储 编译器 Linux
自定义类型——结构体,枚举,联合
自定义类型——结构体,枚举,联合
|
编译器 C++
自定义类型:结构体,枚举,联合 (1)
自定义类型:结构体,枚举,联合 (1)
72 1
|
编译器 C++
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
|
存储 编译器 C++
自定义类型:结构体,枚举,联合 (2)
自定义类型:结构体,枚举,联合 (2)
65 0
|
存储 安全 编译器
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
113 0
|
编译器 C++
自定义类型:结构体、枚举、联合
自定义类型:结构体、枚举、联合
61 0
自定义类型:结构体、枚举、联合
|
存储 C语言
详解自定义类型:结构体,枚举,联合(下)
详解自定义类型:结构体,枚举,联合(下)