枚举(enum)/共用体(union)/结构体(struct)---详解

前言

C语言包含内置类型自定义类型

其实C语言中有内置类型,包含:char,short,int,long,long long,float,double,long double ,这些是C语言本身支持的现成的类型。

但仅仅只有内置类型是远远不够的,在描述一个复杂对象是无法使用内置类型来描述,例如描述一个人,可以通过姓名,身高,性别,体重等来描述,这时就需要使用自定义类型!!

自定义类型包含:结构体(struct),枚举(enum),联合体(union)

自定义类型常常与数据结构关联,所谓的数据结构,其实就是数据在内存中的存储和组织的结构,并且数据结构有很多种,

线性数据结构:顺序表,链表,栈,队列

树形的数据结构:二叉树

图……

想知道其他的内容:请关注石油人单跳所有石油人单挑所有-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/2302_80345385?spm=1011.2415.3001.5343

目录

前言

1----结构体

1-1结构体的声明

1-2结构体变量的创建和初始化

1-3结构体的特殊声明

1-4 结构体的自引用

1-5计算结构的大小

练习1——(规则1,2,3)

练习2——(规则4)

1-6内存对齐的原因

1-7修改默认对齐数

1-6结构体传参

1-7位段

1-7-1认识位段

1-7-2位段的内存分配

1-7-3位段的跨平台问题

1-7-4位段的使用的注意事项

1-7-5位段的拓展

2----联合体

2-1联合体类型的声明

2-2联合体的特点

2-2-1对比结构体和联合体的内存发布情况

2-3联合体的大小计算

2-3-1实际运用

2-4联合体的经典练习

2-4-1 方法1--联合体

2-4-2方法2--字节

3----结构体与联合体区别(重点)

        3-1. 内存利用方面    

        3-2. 成员访问方面       

        3-3. 用途方面         

        3-4  总结

4----枚举

4-1枚举的声明

4-2枚举类型的优点

4-3枚举类型的使用

5----自定义类型的总结

6----警告的总结

7----编程提示的总结


1----结构体

1-1结构体的声明

在声明结构体时,必须列出它包含的所有成员,这个列表包括每个成员的类型和名字,

结构体的成员可能是一个或多个

花括号括起来的是变量列表(成员列表)

结构体的表示形式

假如要描述一个学生,就可以使用结构体类型~~

//结构体的声明
struct students 
{char name[20];//姓名int age;//年龄float score;//成绩char id[20];//身份证号
};//注意:分号不能丢

注意:分号不能丢

在声明结构体时可以使用typedef创建一种新的类型

比如:

typedef struct students
{char name[20];//姓名int age;//年龄float score;//成绩char id[20];//身份证号
}stu;//分号不能丢

这个技巧和声明一个结构标签的效果相同,区别于stu现在是一个类型名但不是结构标签~~

1-2结构体变量的创建和初始化

结构体初始化有两种方式

一种是按照结构体成员的顺序初始化

一种是按指定的顺序初始化

例如:初始化学生的信息,一起看看代码吧~~

//结构体的创建和初始化
#include<stdio.h>
struct students
{char name[20];//姓名int age;//年龄float score;//成绩char id[20];//身份证号
};//分号不能丢
int main()
{//1-按结构体成员的顺序初始化//struct students s = { "张三",18,90.5f,"123456789"};//2-按指定的顺序初始化struct students s = { .name="张三",.age=18,.score=90.5f,.id="123456789" };printf("name:%s\n", s.name);printf("age:%d\n", s.age);printf("score:%f\n", s.score);printf("id:%s\n", s.id);return 0;
}

1-3结构体的特殊声明

在声明结构的时候,可以不完全的声明。(缺少标签)——匿名结构体

比如下面的结构体就是一个匿名结构体:


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

但匿名结构体也存在问题

例如:

//匿名结构体只能使用一次
struct
{char b;int a;float c;
}x;
struct
{char b;int a;float c;
}*ps;
#include<stdio.h>
int main()
{ps = &x;return 0;
}

输出结果:

这段代码与匿名结构体有关

上面的结构在声明的时候省略了结构体的标签。

那么

p=&x;//这是合法的吗?

分析:

编译器会把上面的两个声明当成完全不同的两个类型,所以是非法的。

匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使用一次!!

对匿名结构体的改进

可以使用typedef重命名匿名结构体,这样就可以消除匿名结构体只能使用一次的缺陷!!

当这个结构体只使用一次是可以考虑使用匿名结构体,否则不要考虑!!

当然匿名结构体也可以重命名~~

//改善
typedef struct 
{char b;int a;float c;
}stu;//匿名结构体类型也可以重新命名
#include<stdio.h>
int main()
{stu s;return 0;
}

当然匿名结构体也可以进行初始化~~

​
struct 
{int a;char b;double c;
}s = {18,'A',3.14};//在这里创建变量,也可以初始化,没有标签名
#include<stdio.h>
int main()
{printf("%c %d %lf", s.b, s.a, s.c);return 0;
}​

输出结果:

1-4 结构体的自引用

在结构体中包含一个类型为该结构体本身的成员可以吗?

比如:定义一个链表的节点,其中节点的结构是:(数据域+指针域)/(数据和地址

 struct Node {int data;struct Node next;
};

那么试试计算链表节点这个结构体的大小吧~~

其实这样的引用方式是错误的,因为一个结构体中再包含一个同类型的结构体变量,这样结构体变量的大小就会无穷的大,这是错误的!!

那么看看正确的自引用方式吧~~

 struct Node {int data;//数据struct Node* next;//指针
};

在结构体自引用的过程中,使用typedef对匿名结构体重命名,也容易产生问题,看看下面的代码可行吗?

typedef struct {int data;//数据Node* next;//指针
}Node;

其实这样是不行的,因为Node是对前面的匿名结构体类型的重命名产生的,但在匿名结构体内部提前使用Node类型来创建成员变量,这是不行的!!

解决方案:定义结构体不要使用匿名结构体!!

实例代码如下:

typedef struct Node {int data;//数据struct Node* next;//指针
}Node;

关于结构体的自引用,有两种写法。完整代码如下~~

//结构体的自引用
//匿名的结构体类型是不能实现这种结构体的自引用效果的
#include<stdio.h>
typedef struct Node {int data;//数据struct Node* next;//指针
}Node;
// 写法1struct Node {int data;//数据struct Node* next;//指针
};//写法2
int main()
{struct Node Node1;Node node1;return 0;
}

1-5计算结构的大小

想知道结构体的大小我们得学习结构体内存对齐~~

1-5-1对齐规则

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

1、结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处/(位置)

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

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

VS中默认的值是8

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

3、结构体大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍

4、如果嵌套了结构体,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍数处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍

比如:偏移量是4的倍数,地址便是4的倍数~

试着做这两道练习,检验你是否真的会计算结构体大小~~

注意:VS对齐数一般设为2的整数倍

练习1——(规则1,2,3)

//计算结构体的大小
//内存对齐
#include<stdio.h>
struct S2
{char c1;//1 8 1char c2;//1 8 1int i;//4 8 4
};
int main()
{printf("%zd\n", sizeof(struct S2));return 0;
}

输出结果:

8

解析:

这也可以说明结构体(struct),多个成员,每个成员都有自己独立的空间!!

0——第一个成员存放

练习2——(规则4)

#include<stdio.h>
struct S3
{double d;//8 8 8char c;//1 8 1   所有最大对齐数中最大的是8,那么结构体的大小就是8的倍数int i;//4 8 4float e;//4 8 4
};//大小为24
struct S4
{char c1;//1 8 1struct S3 s3;//看s3里的最大对齐数-8double d;//8 8 8
};
int main()
{	
printf("%zd\n", sizeof(struct S4));//返回size_t
return 0;
}

输出结果:

40

解析:

S3结构体大小的计算

S4结构体大小的计算

结论:对于计算嵌套的结构体的大小,先计算“里面”的结构体的大小,得出“里面”的最大对齐数,再计算外面的结构体的大小。计算嵌套的结构体时偏移量从“里面”的最大对齐数的整数倍开始,偏移“里面”的结构体的大小~~

1-6内存对齐的原因

1、平台原因

2、性能原因

结论:结构体的内存对齐是拿空间换时间的做法~~

在设计结构体是要满足内存对齐,又要节省空间

可以让占用空间小的成员,尽量集中在一起~~

下面这段代码就可以说明这个方法~~

尽管类型成员相同,但它们所占的空间大小有所不同
struct S1
{char c1;//1int i;//4char c2;//1
};
struct S2
{char c1;//1char c2;//1int i;//4
};
int main()
{printf("%zd\n", sizeof(struct S1));//12printf("%zd\n", sizeof(struct S2));//8return 0;
}

输出结果

1-7修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对齐数

#include<stdio.h>
#pragma pack(1)
//#pragma pack(2)
//设置默认对齐数
struct S1
{char c1;//1 1 1 1 2 1int i;//1 4 1   2 4 2char c2;//1 1 1 1 2 1//对齐数为1时,每个成员对齐到数字1上,说明没有对齐//那么连续存放就OK,最终结构体的大小只要是1的倍数就OK
};
#pragma pack()//取消设置的对齐数,还原为默认的
int main()
{printf("%zd\n", sizeof(struct S1));//3return 0;
}

结构体在对齐方式不合适时,可以自己更改默认对齐数~~

1-6结构体传参

#include<stdio.h>
//struct book {
//	char name[20];
//	int price;
//}s = {"简爱",100};//初始化写法1
struct book {char name[20];int price;
};
struct book s={ "简爱",1000 };//初始化写法2
void Print(struct book* ps)
{printf("name->%d\n", ps->price);
}
int main()
{Print(&s);return 0;
}
//结构体传参的时候要传结构体的地址!!

输出结果:

结构体传参的时候要传结构体的地址的原因:

分析:函数传参的时候,参数是需要压栈的,会有时间和空间上系统的开销。

如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致系统的性能下降。

再强调一下结构体传参的时候要传结构体的地址!!

1-7位段

1-7-1认识位段

位段是专门用来节省内存的。

位段声明和结构是类似的,但有所差异~

1、位段的成员必须是int,unsigned int或者signed int,在C99中位段成员的类型也可以选择其他类型

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

位段的声明

struct A
{int _a ;int _b ;//4个字节占32个比特位int _c ;int _d ;int _e ;
};

那么位段的大小怎么计算呢?

例如

位段——“位”:二进制位
struct A
{int _a : 2;//_a只占2个比特位int _b : 5;int _c : 10;int _d : 30;int _e : 31;
};

A就是一个位段,那么A的大小是多少呢?

//位段——位:二进制位
struct A
{int _a : 2;//_a只占2个比特位int _b : 5;int _c : 10;int _d : 30;int _e : 31;
};
#include<stdio.h>
int main()
{printf("%zd\n", sizeof(struct A));//12return 0;
}

输出结果

12

为什么是12呢?想知道这个得知道位段的内存分配~~

1-7-2位段的内存分配

注重可移植性的程序应该避免使用位段。由于下面这些与实现有关的依赖性,位段在不同的系
统中可能有不同的结果。 

1.  int 位段被当作有符号数还是无符号数    
2.位段中位的最大数目。许多编译器把位段成员的长度限制在一个整型值的长度之内,所以一个能够运行于32位整数的机器上的位段声明可能在16位整数的机器上无法运行。
3.位段中的成员在内存中是从左向右分配的还是从右向左分配的。
4.当一个声明指定了两个位段,第2个位段比较大,无法容纳于第1个位段剩余的位时,编译器有可能把第2个位段放在内存的下一个字,也可能直接放在第1个位段后面,从而在两个内存位置的边界上形成重叠。

就这上面的代码,解释上这段吧~~

那么现在可以解释为什么A的大小是12字节了。

图解:

为了再次认识位段的内存分配,看看下面这段代码吧~~

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;
//这个位段的空间是如何开辟的呢?

解析:

例如:存数字0,1,2,3
00-0,01-1,10-2,11-2,两个二进制位就够了,但有30个比特位浪费了
此时就可以使用位段——在一定程度节省内存空间
C语言没有规定标准,剩余空间不够时,是浪费还是继续存放
这就取决于编译器
VS上数据从右往左存,剩余空间不够时,是浪费
#include<stdio.h>
struct S
{char a : 3;//010char b : 4;char c : 5;char d : 4;
};int main()
{struct S s = { 0 };s.a = 10;//1010发生截断,存的是010s.b = 12;s.c = 3;s.d = 4;return 0;
}

图解

调试过程

1-7-3位段的跨平台问题

  1. 根据不同的平台写不同的代码。
  2. 32位和64位的机器上int的长度是4个字节,16位机器上int的长度是2个字节。
  3.  int 位段被当作有符号数还是无符号数    
  4. 位段中位的最大数目。许多编译器把位段成员的长度限制在一个整型值的长度之内,所以一个能够运行于32位整数的机器上的位段声明可能在16位整数的机器上无法运行。
  5. 位段中的成员在内存中是从左向右分配的还是从右向左分配的。
  6. 当一个声明指定了两个位段,第2个位段比较大,无法容纳于第1个位段剩余的位时,编译器有可能把第2个位段放在内存的下一个字,也可能直接放在第1个位段后面,从而在两个内存位置的边界上形成重叠。

1-7-4位段的使用的注意事项

因此不能对位段成员使用&操作符,这样就不能使用scanf函数给位段成员输入值,那么解决方案是:先输入放在一个变量中,然后赋值给位段成员~

//位段的使用
//使用位段的结构体类型中的成员类型应该相同
struct A
{int _a : 2;//_a只占2个比特位int _b : 5;int _c : 10;int _d : 30;int _e : 31;
};
#include<stdio.h>
int main()
{struct A sa = { 0 };int b = 0;scanf("%d", & b);sa._b = b;printf("%zd", sizeof(struct A));return 0;
}

1-7-5位段的拓展


2----联合体

2-1联合体类型的声明

像结构体一样,联合体也是由一个或多个成员构成,这些成员可以是不同的类型。

但编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。

因此联合体也叫共用体

给联合体其中一个成员赋值,其他成员的值也跟着变化

联合体的运用场景:改变c时i也被改变,先改变低地址处。

一般:union与struct不会同时使用~

//联合体类型的声明
#include<stdio.h>
union un {char a;int b;
};
int main()
{union un u = { 0 };//联合体变量的定义//计算联合体变量的大小printf("%zd\n", sizeof(u));return 0;
}

输出结果:

为什么输出结果是4呢?

那要看联合体类型的特点呢~~

2-2联合体的特点

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

看看这两段代码,相信你会对此有深入的理解。

第一段代码

​
#include <stdio.h>
//联合体的声明
union Un
{char c;int i;
};
int main()
{//创建联合体变量union Un un = {0};// 它们的地址大小一样?printf("%p\n", &(un.i));printf("%p\n", &(un.c));printf("%p\n", &un);return 0;
}​

输出结果:

00000045EBFFF764
00000045EBFFF764
00000045EBFFF764

再看看第二段代码

#include <stdio.h>
union Un//联合体的声明
{char c;int i;
};
int main()
{union Un un = { 0 };//联合体变量的创建un.i = 0x11223344;un.c = 0x55;printf("%x\n", un.i);return 0;
}

输出结果:

11223355

从输出结果可以看出,第一段代码输出的地址都一样,而从第二段代码输出结果可以分析,将i的第四个字节的内容修改为55了。

因此可以画出联合体(un)的内存发布图

2-2-1对比结构体和联合体的内存发布情况

我们再对比一下相同成员的结构体和联合体的内存发布情况。

结构体

struct S
{char c;int i;
};

内存分布情况:

联合体:

union un
{char c;int i;
};

内存发布情况:

结论:共用体(union)多个成员,所以成员共用同一块内存空间!!

2-3联合体的大小计算

1、联合体的大小至少是最大成员的大小

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

试着计算下面两个联合体的大小吧~~

// 计算联合体的大小
#include<stdio.h>
union Un1
{char c[5];//1 8 1int i;//4 8 4
};
union Un2
{short c[7];//2 8 2int i;//4 8 4
};
int main()
{union Un1 u1 = { 0 };union Un2 u2 = { 0 };printf("%zd\n", sizeof(u1));printf("%zd\n", sizeof(u2));return 0;
}

输出结果:

解析

联合体Un1的内存发布

联合体Un2的内存发布

联合体是可以节省内存的!!

2-3-1实际运用

比如有一个礼物兑换单,礼物兑换单中三个商品:书,杯子,衬衫。

每一种商品都有库存量,价格,商品类型和商品类型相关的其他信息

书:书名,作者,页数

杯子:设计

衬衫:设计,颜色,尺寸

如果将这些信息简单的一 一罗列在一个结构体中,用起来很方便,但这样使得结构体的大小偏大,比较浪费内存,因为对于兑换单中的商品来说,只有部分属性信息是常用的,比如商品为书,就不需要design,colour,size……

所以可以把公共属性单独写出来,剩余属于各种商品本身的属性使用联合体联合起来,这样在一定程度上节省了内存~~

struct gift_list 
{//公共属性int stock_number;//库存量double price;//价格int type;//商品类型//每个商品具有的自己的属性union {struct {char book_name[20];//书名char author[20];//作者int page;//页数}book;struct {char design[20];//设计}cup;struct  {char design[20];//设计char colour[10];//颜色char size[10];//尺寸}shirt;};
};

2-4联合体的经典练习

写一个小程序判断,你的机器是大端模式还是小端模式

在写程序之前,先来回顾一下大端和小端模式

 大端:数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容保存在内存的低地址处
 小端:数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容保存在内存的高地址处
 例如:0x11223344,在小端模式下,存储的顺序是44332211

在10进制中,例如数字123,1是高位,3是低位,在计算机中从左往右,是从低地址到高地址处的

2-4-1 方法1--联合体

练习判断一个机器是大端还是小端

根据联合体的内存发布特点可以轻松解决

 写法1
#include<stdio.h>
int check_sys()
{union {int a;char b;}sa;sa.a = 1;return sa.b;
}
int main()
{if (check_sys()){printf("小端\n");}else{printf("大端\n");}return 0;
}

2-4-2方法2--字节

练习判断一个机器是大端还是小端

判断一个字节存储的是1还是0

//写法2
​
#include<stdio.h>
int check_sys()
{int i = 1;return (*(char*)(&i));
}
int main()
{if (check_sys()){printf("小端\n");}else{printf("大端\n");}return 0;
}​

本电脑的输出结果:

小端


3----结构体与联合体区别(重点)

        C语言中结构体(struct)与联合体(union)是两种不同的数据结构,它们的主要区别在于内存利用、成员访问和用途。具体分析如下:

        3-1. 内存利用方面    

          结构体中每个成员占用独立的内存空间,而联合体的所有成员共享同一块内存空间。这意味着一个结构体变量的总长度等于所有成员的长度之和,而一个联合体变量的总长度至少能容纳最大的成员变量,并且要满足是所有成员变量类型大小的整数倍。

        3-2. 成员访问方面       

        在结构体中,可以同时访问每个成员,因为它们各自拥有独立的存储空间;而在联合体中,只能同时访问其中一个成员,因为所有成员共用相同的存储空间。

        3-3. 用途方面         

        结构体通常用于将不同类型的数据组合成一个整体,以自定义数据类型的形式来使用;而联合体则用于让几个不同类型的变量共占一段内存,这些变量会相互覆盖,通常用于节省内存或者处理不同类型数据的交替存储。

        3-4  总结

        总结来说,结构体适合用于需要同时存储和访问多个不同类型数据的情况,而联合体则适用于只需要存储一组数据中的某一个,或者需要共享内存空间以节省内存的场合。了解这两者的区别对于编写高效、可维护的代码非常重要。通过合理选择使用结构体或联合体,可以优化程序的内存使用,提高执行效率。


4----枚举

4-1枚举的声明

枚举字面意思就是一 一列举,把可能的值一 一列举。

比如:性别:男、女,可以一 一列举

三原色:红、绿、蓝,也可以一 一列举~

这些数据的表示就可以使用枚举!!

比如三原色使用枚举类型表示:

//枚举类型的声明
enum Colour {RED ,GREEN ,BLUE ,
};

上面定义的enum Colour是枚举类型,{ }中的内容是枚举类型的可能取值,也叫枚举常量。

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

比如:

enum Colour{RED = 2,GREEN = 4,BLUE = 6,
};

4-2枚举类型的优点

之前我们学习了#define定义常量,那么枚举类型与之有什么不同呢?

4-3枚举类型的使用

enum Colour{RED = 2,GREEN = 4,BLUE = 6,
};
enum Colour clr = GREEN;//使用枚举常量给枚举变量赋值

C语言中可以拿整数给枚举变量赋值,但在C++中不行!!


5----自定义类型的总结

  • 1、        在结构中,不同类型的值可以存储在一起。结构中的值称为成员,它们是通过名字访问的。结构变量是一个标量,可以出现在普通标量变量可以出现的任何场合。 

  • 2、        结构的声明列出了结构包含的成员列表。不同的结构声明即使它们的成员列表相同也被认为是不同的类型。结构标签是一个名字,它与一个成员列表相关联。你可以使用结构标签在不同的声明中创建相同类型的结构变量,这样就不用每次在声明中重复成员列表。typedef也可以用于实现这个目标。

  • 3、        结构的成员可以是标量、数组或指针。结构也可以包含本身也是结构的成员。在不同的结构中出现同样的成员名是不会引起冲突的。你使用点操作符访问结构变量的成员。如果你拥有一个指向结构的指针,你可以使用箭头操作符访问这个结构的成员。

  • 4、        结构不能包含类型也是这个结构的成员,但它的成员可以是一个指向这个结构的指针。这个技巧常常用于链式数据结构中。为了声明两个结构,每个结构都包含一个指向对方的指针的成员,我们需要使用不完整的声明来定义一个结构标签名。结构变量可以用一个由花括号包围的值列表进行初始化。这些值的类型必须适合它所初始化的那些成员。

  •  5、       编译器为一个结构变量的成员分配内存时要满足它们的边界对齐要求。在实现结构存储的边界对齐时,可能会浪费一部分内存空间。根据边界对齐要求降序排列结构成员可以最大限度地减少结构存储中浪费的内存空间。sizeof 返回的值包含了结构中浪费的内存空间。

  • 6、        结构可以作为参数传递给函数,也可以作为返回值从函数返回。但是,向函数传递一个指向结构的指针往往效率更高。在结构指针参数的声明中可以加上const 关键字防止函数修改指针所指向的结构。

  •  7、       位段是结构的一种,但它的成员长度以位为单位指定。位段声明在本质上是不可移植的,因为它涉及许多与实现有关的因素。但是,位段允许你把长度为奇数的值包装在一起以节省存储空间。源代码如果需要访问一个值内部任意的一些位,使用位段比较简便。

  • 8、        一个联合的所有成员都存储于同一个内存位置。通过访问不同类型的联合成员,内存中相同的位组合可以被解释为不同的东西。联合在实现变体记录时很有用,但程序员必须负责确认实际存储的是哪个变体并选择正确的联合成员以便访问数据。联合变量也可以进行初始化,但初始值必须与联合第1个成员的类型匹配

6----警告的总结


1.具有相同成员列表的结构声明产生不同类型的变量。
2.使用typedef 为一个自引用的结构定义名字时应该小心。
3.向函数传递结构参数是低效的。


7----编程提示的总结


1.        把结构标签声明和结构的 typedef 声明放在头文件中,当源文件需要这些声明时可以通过#include指令把它们包含进来。
2.        结构成员的最佳排列形式并不一定就是考虑边界对齐而浪费内存空间最少的那种排列形式。

3.把位段成员显式地声明为signed int或unsigned int类型。
4.位段是不可移植的。
5.位段使源代码中位的操作表达得更为清楚

制作不易,老铁们三连吧,别下次一定了!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/316258.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux工具篇 之 vim概念 操作 及基础指令讲解

学校不大 创造神话 讲桌两旁 陨落的王 临时抱佛脚 佛踹我一脚 书山有路勤为径 游戏玩的很起劲 想要计算机学的好&#xff0c;我的博客列表是个宝 –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀…

前端学习笔记3

列表、表格与表单​ 列表就是信息资源的一种展示形式。它可以使信息结构化和条理化,并以列表的样式显示出来,以便浏览者能更快捷地获得相应的信息。 3.0 代码访问地址 https://gitee.com/qiangge95243611/java118/tree/master/web/day03 3.1 列表 ​ 列表大致可以分为3类…

怎么给字符串字段加索引?

怎么给字符串字段加索引&#xff1f; 现在&#xff0c;几乎所有的系统都支持邮箱登录&#xff0c;如何在邮箱这样的字段上建立合理的索引&#xff0c;是我们今天要讨论的问题。 假设&#xff0c;你现在维护一个支持邮箱登录的系统&#xff0c;用户表是这么定义的&#xff1a; …

如何实现直播声卡反向给手机充电功能呢?

在数字化时代的浪潮中&#xff0c;声卡作为多媒体系统的核心组件&#xff0c;扮演着声波与数字信号相互转换的关键角色。它不仅能够将来自各类音源的原始声音信号转换为数字信号&#xff0c;进而输出到各类声响设备&#xff0c;更能够通过音乐设备数字接口(MIDI)发出合成乐器的…

STM32点灯大师(点了一颗LED灯,轮询法)

配置操作&#xff1a; 一、使用CubeMX配置到大致的操作 1.1 选择芯片 1.2 选择引脚&#xff08;根据电路图&#xff09; 1.3 配置gpio口 1.4 配置系统 1.5文件项目操作 最后就是点击 二、点击CubeMX生成的代码&#xff0c;并且修改代码 2.1 看看效果 2.2 写代码

架构师技能:技术深度硬实力透过问题看本质--深入分析nginx偶尔502错误根因

以架构师的能力标准去分析每个问题&#xff0c;过后由表及里分析问题的本质&#xff0c;复盘总结经验&#xff0c;并把总结内容记录下来。当你解决各种各样的问题&#xff0c;也就积累了丰富的解决问题的经验&#xff0c;解决问题的能力也将自然得到极大的提升。励志做架构师的…

Linux|awk 特殊模式“BEGIN 和 END”

引言 在本文[1]&#xff0c;我们将介绍Awk的更多特性&#xff0c;特别是两个特殊的模式&#xff1a;BEGIN和END。 这些独特的功能在我们努力扩展和深入探索构建复杂Awk操作的多种方法时&#xff0c;将大有裨益。 实例 让我们从Awk系列的开篇回顾开始&#xff0c;回想一下&#…

2024抖音AI图文带货班:在这个赛道上 乘风破浪 拿到好效果

课程目录 1-1.1 AI图文学习指南 1.mp4 2-1.2 图文带货的新机会 1.mp4 3-1.3 2024年优质图文新标准 1.mp4 4-1.4 图文如何避免违规 1.mp4 5-1.5 优质图文模板解析 1.mp4 6-2.1 老号重启 快速破局 1.mp4 7-2.2 新号起号 不走弯路 1.mp4 8-2.3 找准对标 弯道超车 1.mp4 9…

DRF学习之三大认证

一、认证 1、自定义认证 在前面说的 APIView 中封装了三大认证&#xff0c;分别为认证、权限、频率。认证即登录认证&#xff0c;权限表示该用户是否有权限访问接口&#xff0c;频率表示用户指定时间内能访问接口的次数。整个请求最开始的也是认证。 &#xff08;1&#xff…

Qt : 在QTreeWidget中添加自定义右键菜单

一、引言 如图&#xff0c;我们需要在一个QTreeWidget 控件中添加了自定义右键菜单。 二、思路 如何做到的呢&#xff0c;很简单。浅浅记录和分享一下。 继承QTreeWidget&#xff0c;定义一个子类CustomTreeWidget &#xff0c;在重写contextMenuEvent 事件即可。 三、代…

基于 Spring Boot 博客系统开发(二)

基于 Spring Boot 博客系统开发&#xff08;二&#xff09; 本系统是简易的个人博客系统开发&#xff0c;为了更加熟练地掌握SprIng Boot 框架及相关技术的使用。&#x1f33f;&#x1f33f;&#x1f33f; 基于 Spring Boot 博客系统开发&#xff08;一&#xff09;&#x1f4…

PHP 错误 Unparenthesized `a ? b : c ? d : e` is not supported

最近在一个新的服务器上测试一些老代码的时候得到了类似上面的错误&#xff1a; [Thu Apr 25 07:37:34.139768 2024] [php:error] [pid 691410] [client 192.168.1.229:57183] PHP Fatal error: Unparenthesized a ? b : c ? d : e is not supported. Use either (a ? b : …

语音识别的基本概念

语音识别的基本概念​​​​​​​ ​​​​​​​ 言语是一种复杂的现象。人们很少了解它是如何产生和感知的。天真的想法常常是语音是由单词构成的&#xff0c;而每个单词又由音素组成。不幸的是&#xff0c;现实却大不相同。语音是一个动态过程&#xff0c;没有明确区分的…

Baidu comate智能编程助手评测

Baidu comate智能编程助手评测 作者&#xff1a;知孤云出岫 目录 一&#xff0e; 关于comate产品 二&#xff0e; 关于comate产品体验 三&#xff0e; 关于实际案例. 四&#xff0e; 关于baidu comate编程助手的实测体验感悟 五&#xff0e; …

如何快速申请SSL证书实现HTTPS访问?

申请SSL证书最简单的方法通常涉及以下几个步骤&#xff0c;尽量简化了操作流程和所需专业知识&#xff1a; 步骤一&#xff1a;选择适合的SSL证书类型 根据您的网站需求&#xff0c;选择最基础的域名验证型&#xff08;DV SSL&#xff09;证书&#xff0c;它通常只需验证域名所…

从 MySQL 到 ClickHouse 实时数据同步 —— Debezium + Kafka 表引擎

目录 一、总体架构 二、安装配置 MySQL 主从复制 三、安装配置 ClickHouse 集群 四、安装 JDK 五、安装配置 Zookeeper 集群 六、安装配置 Kafaka 集群 七、安装配置 Debezium-Connector-MySQL 插件 1. 创建插件目录 2. 解压文件到插件目录 3. 配置 Kafka Connector …

Profinet转Modbus网关接称重设备与1200PLC通讯

Profinet转Modbus网关&#xff08;XD-MDPN100&#xff09;是一种能够实现Modbus协议和Profinet协议之间转换的设备。Profinet转Modbus网关可提供单个或多个RS485接口&#xff0c;使用Profinet转Modbus网关将称重设备与西门子1200 PLC进行通讯&#xff0c;可以避免繁琐的编程和配…

XY_RE复现(二)

一&#xff0c;何须相思煮余年 0x55 0x8b 0xec 0x81 0xec 0xa8 0x0 0x0 0x0 0xa1 0x0 0x40 0x41 0x0 0x33 0xc5 0x89 0x45 0xfc 0x68 0x9c 0x0 0x0 0x0 0x6a 0x0 0x8d 0x85 0x60 0xff 0xff 0xff 0x50 0xe8 0x7a 0xc 0x0 0x0 0x83 0xc4…

YOLOv8+PyQt5输电线路缺陷检测(目前最全面的类别检测,可以从图像、视频和摄像头三种路径检测)

1.效果视频&#xff1a;YOLOv8PyQt5输电线路缺陷检测&#xff08;目前最全面的类别检测&#xff0c;可以从图像、视频和摄像头三种路径检测&#xff09;_哔哩哔哩_bilibili 资源包含可视化的输电线路缺陷检测系统&#xff0c;可识别图片和视频当中出现的五类常见的输电线路缺陷…

Virtualbox7.0.10--在虚拟机中安装Ubuntu20.04

前言 下载Virtualbox7.0.10&#xff0c;可参考《Virtualbox–下载指定版本》 Virtualbox7.0.10具体安装步骤&#xff0c;可参考《Virtualbox7.0.10的安装步骤》 Virtualbox7.0.10创建虚拟机&#xff0c;可参考《Virtualbox7.0.10–创建虚拟机》 Virtualbox7.0.10安装Ubuntu20.0…