目录
结构体
结构体的基础知识:
结构体的声明:
特殊声明:
结构体的自引用
结构体变量的定义和初始化
结构体内存对齐:
修改默认对齐数:
结构体传参
结构体的柔型数组
柔型数组的书写
柔性数组的特点
柔性数组的使用
柔性数组的优势
位段
什么是位段
位段的内存分配
位段的跨平台问题
位段的使用
枚举
枚举类型的定义
枚举的优点
枚举的使用
联合(共用体)
联合类型的定义
联合的特点
联合大小的计算
联合面试题
结构体
结构体的基础知识:
结构是一些值的集合,这些值被叫做成员变量,这些成员变量可以是不同的类型
结构体的声明:
结构体关键字:struct ,用struct关键字来声明一个结构体,声明规则如下:
// tag是结构体标签 //member-list 是成员变量列表 //variable-list 是结构体变量列表,这里定义的变量是结构体全局变量 struct tag//结构体标签 { //是成员变量列表 member-list }variable-list; //是结构体变量列表,这里定义的变量是结构体全局变量
创建一个学生类型:
//用结构体描述一个学生类型 //创建学生类型 struct Student { char name[20];//名字 int age;//年龄 char sex[5];//性别 char id[20];//学号 }; //分号不能丢
特殊声明:
在声明结构体的时候,可不完全声明,也就是,结构体类型在声明的时候,省略掉了结构体标签(tag),此时的结构体类型我们可以理解为没有名字(标签)的结构体,此结构体我们称为匿名结构体,匿名结构体,只有在定义的同时创建变量,此时创建的变量是结构体全局变量,不能单独使用此类型创建变量,不能用一个结构体指针去指向另一个结构体,这样是不合法的,哪怕这两个结构体的成员变量完全相同,也是不合法的,编译器会把两个结构体的声明,看做是完全不同的两种类型,因为类型不同,所以不同类型的指针指向一种类型的变量是不合法的(等同于用 int 类型的指针指向 double类型的变量,是非法的),匿名结构体具体该如何声明定义呢?具体看以下代码:
//匿名结构体类型 struct { int a; char b; float c; }x;// x是结构体变量 struct { int a; char b; float c; }a[20], *p;//a是结构体数组,p是结构体指针变量 //上面两个结构体就是匿名结构体, //两个结构体都省略了标签名 //匿名结构体只有在定义的时候创建结构体变量 //不能单独使用匿名结构体创建结构体变量! //有一个重点: int main() { p=&x; //这条语句是不合法的 //虽然这两个结构体成员变量相同 //但在编译器的角度是把它们看做不同类型的两种数据 //编译器会把它们的两个声明看成是完全不同的两种类型 //所以是非法的 return 0; }
结构体的自引用
我们知道结构体的成员可以是不同类型的,所以结构体成员也可以是结构体类型,那么我们就可以通过一个结构体访问另一个结构体,既然结构体的成员变量可以是结构体,那么我们思考一个问题,一个结构体成员列表中是否可以存放这个结构体自身呢?也就是通过它的成员变量来访问自身(结构体的自引用),该如何通过它的成员变量访问到自身呢?我们在自引用的时候只能用它的结构体指针来访问它自身,不能直接在成员变量中放入它自身创建的结构体变量去访问,(因为结构体变量是要开辟空间的,我们在自引用的时候写到成员变量的位置,还不确定此结构体究竟有多大,无法知道它的大小,所以用结构体变量不合适,是非法的,因为该结构体类型还没创建出来,而用它自身的结构体指针,只要是指针它的大小就是确定32位下是4个字节,64位下是8个字节,所以我们确切的知道结构体该成员的大小,是合法的),具体如下代码:
1、通过一个结构体访问另一个结构体:
//通过一个结构体访问另一个结构体 // //通过结构体变量访问 struct A { int a; char b; float c; }; struct B { int a; char b; struct A ss;//创建一个A结构体类型变量ss,可通过ss变量访问结构体A float c; }; //通过结构体指针访问 struct C { int a; float b; char c; }; struct D { int a; float b; struct C* p;//创建一个C结构体类型指针p,可通过指针p方位内结构体C char c; }; int main() { //1、成员变量是结构体变量的方式访问另一个结构体 //定义B结构体变量bb 并初始化 struct B bb = { 10,'a',{3,'r',3.25},3.14 }; //通过B结构体成员变量访问结构体A printf("%d %c %.2f\n", bb.ss.a, bb.ss.b, bb.ss.c); //2、成员变量是结构体指针的方式访问另一个结构体 //创建C结构体变量cc并初始化 struct C cc = { 4,4.4,'a' }; //创建D结构体变量dd并初始化 struct D dd = { 5,5.5,&cc,'b' };//让D结构体中的成员变量p指向 C结构体的变量cc //通过D结构体的成员变量p访问C结构体的变量 printf("%d %.2f %c\n", dd.p->a, dd.p->b, dd.p->c); return 0; }
2、结构体自身引用自己
#include <stdio.h> #include <stdlib.h> //结构体自己引用自己 错误的引用方式 //struct Stun //{ // char name[10];//姓名 // int age;//年龄 // char eax[5];//性别 // struct Stun student;//创建Stun结构体变量 //}; //正确的引用方式 struct Stu { char name[10]; int age; char eax[5]; struct Stu* p;//创建Stu结构体指针 }; int main() { //Stu结构体成员p指针自己引用自己 struct Stu ss = { "张三",18,"男",&ss }; //通过自己的成员指针访问自己 printf("%s %d %s\n", ss.p->name, ss.p->age, ss.p->eax); return 0; }
结构体变量的定义和初始化
结构体是我们自定义的类型,它也是一种类型,我们知道通过类型是可以创建变量的,如:通过整型int创建整型变量,通过浮点型创建浮点型变量........,所以通过我们自定义的结构体类型也是可以创建变量的,而变量是可以初始化的,结构体变量也可以初始化,那么结构体变量究竟如何定义又如何初始化呢? 具体如何做,以代码的形式进行注释说明:
#include <stdio.h> #include <stdlib.h> //创建结构体类型 struct pp { int a; float b; char c; }s1;// 创建结构体全局变量s1 struct pp s2;//创建结构体全局变量s2 //s1和s2 都是全局变量 struct stu { int a; int b; int c; }t1={12,13,14};//定义全局变量且同时初始化 struct stu t2 = { 1,2,3 };//定义全局变量并初始化 //用typedef重命名的结构体类型不能直接在括号后面创建全局变量 //因为括号后面要写结构体的新名字 typedef struct sinput { float a; float b; float c; }ss; ss n1;//通过新名字创建变量 //用一个结构体访问其他结构体 struct A { int a; struct pp s4; struct stu* t4; }m1 = { 12,{6,3.55,'c'},NULL};//结构体嵌套初始化 struct A m2 = { 45,{58,2.66,'p'},&t2 };//结构体嵌套初始化 int main() { struct pp s3;//定义结构体变量 是局部变量 struct stu t3 = { 4,5,6 };//定义局部变量并初始化 ss n2 = { 3.14,2.56,4.23 }; //通过新名字创建变量并初始化 struct A m3 = { 34,{56,3.99,'q'},&t1 };//结构体嵌套初始化 return 0; }
结构体内存对齐:
从以上内容,我们大致了解了结构体的使用,那么一个结构体类型的大小是多少呢?也就是一个结构体类型在内存中占用字节的个数,因为结构体的成员变量的类型是不同的,所以结构体没有特定的大小,此时我们要知道结构体的大小,就得自己通过计算得到一个结构体类型的大小,那么结构体类型的大小该怎么计算呢?是直接将其成员类型的大小加起来嘛(这种计算方法是错误的),而正确的计算方法是:结构体的内存对齐,要按照内存对齐规则,来计算结构体的大小
结构体内存对齐规则:
1、第一个成员在与结构体变量偏移量为0的地址处一字节一字节的开始存放
2、其它成员要对齐到对齐数的整数倍处
(就是从这个对齐数的整数倍处的偏移量位置开始存放)
对齐数 = 编译器默认的对齐数 与 该成员大小的 较小值 (vs的默认对齐数是8)
3、结构体的总大小为最大对齐数(每个成员都有一个对齐数)的整数倍
4、嵌套结构体的情况,嵌套的那个结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍!
用vs编译器为例,讲解几个例子:
代码1:
#include <stido.h> struct poin { int a; char b; float c; }; int main() { //打印结构体大小 printf("%zd\n", sizeof(struct poin));//大小为12 return 0; }
解析:
答案:12
看图简单明了:
代码2:
#include <stdio.h> struct poin { int a; char b; float c; }; struct ps { int a; struct poin s1; char b; }; int main() { //打印结构体的大小 printf("%zd\n", sizeof(struct ps));//大小是20 return 0; }
解析:
答案:20
看图简单明了:
为什么要有内存对齐?
有两种说法:
1、平台原因(移植原因)
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常,所以将数据对齐到它能访问到的地址处,以便于硬件平台的访问读取!
2、性能原因数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说:
结构体的内存对齐是拿空间来换取时间的做法
修改默认对齐数:结构体在对齐方式不合适的时候,我们可以自己修改结构体的默认对齐数,我们用 #pragma 这个预处理指令来修改默认对齐数!具体实现看代码:
#include <stdio.h> //将结构体 S1 的默认对齐数设置为5 #pragma pack(5)//设置默认对齐数为5 struct S1 { char c1; int i; char c2; }; #pragma pack()//取消设置的默认对齐数,还原为默认 //将结构体 S2 的默认对齐数设置为1 #pragma pack(1)//设置默认对齐数为1 struct S2 { char c1; int i; char c2; }; #pragma pack()//取消设置的默认对齐数,还原为默认 int main() { //输出的结果是什么? printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0; }
结构体传参
对于结构体传参,我们传结构体本身,跟指针都可以,但建议传结构体指针,因为结构体在传参的时候会有压栈操作,当把结构体本身传过来,如果结构体过大,参数压栈的系统开销就比较大,性能就相对比较弱,可若是传指针,只传过去一个指针,压栈开销较小,性价比较高,所以结构体传参的时候尽量传指针是一个好的选择!
看以下代码:
#include <stdio.h> 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); //传地址 //print2首选 return 0; }
总结:结构体在传参的时候,要传结构体的地址!
结构体的柔型数组
自C99标准开始规定:结构体中的最后一个成员可以是未知大小的数组,而这个数组就叫柔性数组
柔型数组的书写
两种书写方式:
1、在给定数组大小的时候什么都不写
2、数组的大小给定为0
由于编译器的不同,柔性数组的书写方式也就出现了分歧,有些编译器支持只第一种书写方式,而有些只支持第二种书写方式
具体如下代码:
//第一种 typedef struct st_type { int i; int a[];//柔性数组成员 }type_a; //第二种 typedef struct st_type { int i; int a[0];//柔性数组成员 }type_b;
柔性数组的特点
柔性数组有三大特点:
1、结构中的柔性数组成员前面必须至少有一个其他成员。
2、sizeof 返回的这种结构大小不包括柔性数组的内存。3、包含柔性数组成员的结构用malloc ()函数(在主页动态内存管理这篇文章中有详细介绍)进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
具体看代码:
#include <stdio.h> typedef struct st_type { int i; //柔性数组前面必须至少要有一个其它成员 int a[0];//柔性数组成员 }type_a; int main() { //结构的大小不包含柔性数组的内存 printf("%d\n", sizeof(type_a));//4 return 0; }
柔性数组的使用
我们知道了柔性数组的概念,以及特点,那柔性数组该怎么使用呢?其实很简单就是用malloc在堆区给柔性数组开辟一块空间供柔性数组使用,但在开辟空间的时候要将柔性数组之前的结构成员所占用的大小字节要加上,用结构体指针来接收开辟好的空间,此时可以通过结构体指针来访问给柔性数组开辟的空间了!
具体看代码;
#include <stdio.h> struct PP { int a; int arr[0];//柔性数组成员 }; int main() { //创建结构体指针 struct PP* ptr=NULL; //用结构体指针来接收开辟好的空间,且给柔性数组开辟了10个整型空间 ptr = (struct PP*)malloc(sizeof(struct PP) + 10 * sizeof(int)); //进行访问 ptr->a = 49;//给结构成员a赋值为49 //访问柔性数组空间,且给其赋值 int i = 0; for (i = 0; i < 10; i++) { ptr->arr[i] = i + 1; } //打印柔性数组的内容 for (i = 0; i < 10; i++) { printf("%d ", ptr->arr[i]); } free(ptr);//将malloc开辟的堆区空间进行释放 ptr = NULL;//将指针置为空,避免野指针 return 0; }
柔性数组的优势
对于上述柔性数组使用的代码,我们可以直接在结构里面定义一个整型指针来实现,直接用malloc开辟10个整型的空间让结构体的指针来接收,也是可以实现上述的使用的,
具体看代码:
#include <stdio.h> struct PP { int a; int* arr;//整型指针 }; int main() { //创建结构体指针 struct PP* ptr = NULL; //开辟好整型指针之前的成员的空间用ptr接收 ptr = (struct PP*)malloc(sizeof(struct PP)); //开辟10个整型空间,让arr指针接收 ptr->arr = (int*)malloc(sizeof(int) * 10); //进行访问 ptr->a = 49;//给结构成员a赋值为49 //访问柔性数组空间,且给其赋值 int i = 0; for (i = 0; i < 10; i++) { ptr->arr[i] = i + 1; } //打印柔性数组的内容 for (i = 0; i < 10; i++) { printf("%d ", ptr->arr[i]); } free(ptr->arr);//将malloc开辟的10个整型空间释放 ptr->arr = NULL;//将结构成员的整型指针arr置为NULL,避免野指针 free(ptr);//将malloc为整型指针前面的成员开辟的堆区空间进行释放 ptr = NULL;//将指针置为空,避免野指针 return 0; }
此代码在申请空间的时候申请了两次,两次空间是分开申请的,而在free的时候释放了两次指针,由此我们对比可看出,柔性数组比指针更加有优势!
柔性数组的优势:
1、方便内存释放
当我们在函数里写了上述整型指针接收空间的代码,这时候若是只返回结构体指针,用户最后在使用的时候最后只释放了结构体指针指向的空间,而整型指针成员申请的空间不会被释放,函数返回之后也没人知道它的存在,也不能再找到它的位置进行释放,这是一个弊端,然而你用柔性数组的时候,把结构体的内存以及其成员要的内存一次性分配好当把结构体的指针传过来,在释放的时候会将所有申请的空间,一次性释放干净!
2、有利于访问速度
在内存中我们申请空间的时候,每一块我们所用到的空间与空间之间是有间距的,而这个间距我们称之为:内存碎片,上述例子我们用指针成员申请空间的时候,会申请两块空间,此时产生内存碎片较多,而当我们用柔性数组之间申请一块内存空间的时候,此时产生的内存碎片就少!
位段
什么是位段
位段相对于结构体而言,就是为了节省空间,位段里面的成员占用的空间的大小是我们自己定义的,位段的声明跟结构体是类似的,只有两点不同:
1、位段的成员必须是整型家族(int,unsigned int,signed int ,char....)
2、位段的成员后面有一个冒号和数字(数字就是该成员占用的位数,是我们自己定义的)
定义一个位段:
//A就是一个位段 //冒号后面的数字就是这个成员所占用的字节数 struct A { int a : 2; int b : 5; int c : 10; int d : 30; };
位段的内存分配
我们知道了位段的定义,那位段的大小,以及它的内存分配是怎样的呢?那下面我们来逐一了解位段,在了解之前我们得先清楚的知道三个规则:
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
分配空间:位段在分配空间的时候,是先按照成员类型,开辟1个或者4个字节的空间,然后将成员变量从上往下,按照他们后面的数字,也就是它们所占用的位数(比特位),来进行截断存放,当开辟的1个或者4个字节的空间放不下其中的一个成员变量的时候,再继续开辟1个或者4个字节的空间,直到将所有成员所占用的位数(比特位)放完为止,最后开辟的1个或者4个字节的空间的总和就是位段的总大小,也就是位段占用的字节数!
求位段的大小
如下代码:
#include <stdio.h> struct S { char a:3; char b:4; char c:5; char d:4; }; struct S s = {0}; //空间是如何开辟的? int main() { s.a = 10; s.b = 12; s.c = 3; s.d = 4; printf("%zd\n",sizeof(struct S)); return 0; }
解析:
答案:3
画图解释:
位段的跨平台问题
位段有跨平台的问题,位段的跨平台性很差,所谓跨平台,通俗点说就是,系统跟机器的位数不一样,就是不同的平台,计算机硬件+操作系统就是一个平台,有的机器是大端存储,有的机器是小端存储,有32位的机器,也有64位的机器,有不同的操作系统,也有不同的计算机硬件,所有就存在很多平台,而跨平台性就是能否在各种情况下去使用这段代码,在任何平台上功能都是相同的,这样的意思。
位段的跨平台性就很差,原因有四个:
1. int 位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是 舍弃剩余的位还是利用,这是不确定的。
跟结构体相比,位段更加有利于节省空间,但位段具有跨平台的问题,使用需要看实际情况,看自己的代码是否要考虑跨平台性能!
位段的使用
对一些需要分开讨论的数据分类,假设对其进行进行模块化的划分,几个字节表示啥,又几个字节表示啥,这个时候就要用到位段了,可以给其知道要占用的位数,后续在工作中我们将会彻底了解位段的用处!
枚举
枚举就是把可能的取值一一列举出来,比如现实生活中,一周的星期一到星期天有限的7天,可以一一列举出来,还有性别有男有女也可以一一列举,月份有12个月,也可以一一列举等等......这些东西都可以以常量的形式一一列举出来,枚举类型又被叫做枚举常量,它里面存放的成员都是常量,可以说它是一些常量的集合!那么枚举类型如何定义,又如何使用呢?我们耐心往下看:
枚举类型的定义
枚举关键字enum ,用枚举关键字来定义枚举类型,enum+标签名+大括号+枚举常量列表,就可以定义一个枚举类型,具体实现看代码:
enum poin //poin是枚举标签 { //常量列表 constant_list };
我们实际定义几个枚举类型如下代码:
//将一星期一一列举出来 enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; //将性别一一列举出来 enum Sex//性别 { MALE, FEMALE, SECRET }; //将三原色列举出来 enum Color//颜色 { RED, GREEN, BLUE };
以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。{}中的内容是枚举类型的可能取值,也叫 枚举常量 。
这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值,赋值后的那个枚举常量后面的取值是从那个位置开始自上而下一次递增1,而被赋值的那个枚举常量前面的取值还是从0开始一次递增1,具体看代码解释:
//枚举类型可以定义在主函数外面,也可以定义在主函数里面 //但定义在主函数里面的话这个枚举类型只能在主函数内部使用 enum P { A, B, C, D }; int main() { //枚举类型P中,当不给任何常量赋初始值 //值自上而下从0开始一次递增1 printf("%d\n", A);//0 printf("%d\n", B);//1 printf("%d\n", C);//2 printf("%d\n", D);//3 enum Q { AA, BB = 20, CC, DD }; //枚举类型Q中,给Q赋值20时,往后的常量依次增加1, //而前面的常量还是从0开始递增1 printf("%d\n", AA);//0 printf("%d\n", BB);//20 printf("%d\n", CC);//21 printf("%d\n", DD);//22 return 0; }
枚举的优点
我们知道枚举的成员都是常量,那既然是常量,我们用#define来定义不就行了,为什么要有枚举呢?枚举相对于#define是有很多优点的:
枚举的优点:
1、增加代码的可读性和可维护性
2、枚举是一种类型,有类型检查,更加严谨,#define无类型检查
3、防止常量命名污染(封装起来的)
4、便于调试
5、使用方便,一次可以定义多个常量,而#define一次只能定义一个
枚举的使用
枚举是是一种类型,我们知道是类型就可以创建变量,那么枚举类型也可以创建变量,而枚举类型变变量的赋值,只能拿枚举常量,也就是枚举类型的可能取值来赋值,若是赋其他值,会存在类型差异,枚举类型具体该如何使用呢?如下代码:
#include <stdio.h> enum Color//颜色 { RED = 1, GREEN = 2, BLUE = 4 }; enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。 // clr = 5; //ok?? 枚举变量在初始化之后不能再改变其值,因为它具有常量属性不可被修改 int main() { printf("%d\n", clr); return 0; }
联合(共用体)
联合类型的定义
联合关键字 union 联合也是一种特殊的自定义类型,联合类型的定义也包含一系列的成员,联合的特征是这些成员共用同一片空间(所以联合体也叫共用体)。联合体也是一种类型,是类型就可以定义变量,那么联合体类型该怎么声明和定义变量呢?具体看以下代码:
#include <stdio.h> //联合体类型的声明 union Un { char a; int b; float c; }; int main() { //联合变量的定义 union Un ss; //计算联合体的大小, //因为联合体的成员共用同一片空间, //所以联合体至少要能容纳下成员中占用空间最大的成员的大小 printf("%zd\n", sizeof(ss));//4 return 0; }
联合的特点
联合体的成员是共用同一块内存空间的,由此可知,一个联合体的大小至少是最大成员的大小(因为联合体至少得有能力保存最大的那个成员)。联合体的特点就是所用成员共用一片空间,但是几个成员不能同时使用一片空间,但一个成员在使用的时候其它成员不能使用,直到使用结束其它成员才可以使用!联合体的使用其实就是从最低位开始,由低到高每个成员类型不同占用(访问)的空间不同,画图大致理解:
看完图之后我们再看一份代码,加深理解:
#include <stdio.h> union Un { int i; char c; }; union Un un;//创建联合全局变量 int main() { //因为共用同一片空间, // &地址的时候,取出来的是最低位的地址,所以取出来的地址相同! //联合的成员是从低到高访问的 printf("%d\n", &(un.i)); printf("%d\n", &(un.c)); return 0; }
联合大小的计算
我们知道联合的特点就是共用同一片内存空间,联合的大小至少是最大成员的大小,看以下代码:
#include <stdio.h> union Un1 { char c[5]; int i; }; union Un2 { short c[7]; int i; }; //下面输出的结果是什么? int main() { printf("%d\n", sizeof(union Un1)); printf("%d\n", sizeof(union Un2)); return 0; }
代码解析:
答案:8 16
为什么会是 8 和16呢?我们知道联合的大小至少是最大成员的大小,这里面注意两个字,至少,说明联合的大小可能还要比最大成员的大小 大一些,那么联合的大小究竟是怎样计算得来的呢?
计算规则:
1、联合体的大小至少是最大成员的大小
2、当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍(关于对齐数,我们上面说结构体的时候已经说过了!)
那我们回头再看这个代码,画图说明:
仔细看图理解,我们就可理解联合体的大小是如何计算的了
联合面试题
题目:用联合体判断当前机器是小端字节序存储还是大端字节序存储!
分析:这道题,我们最重要的就是要知道联合体的特点:联合体的成员共用块内存空间,在共用的时候是从低地址往高地址访问,类型多大访问的空间就多大,通过这个思路,我们可以创建一个联合体类型,往联合体里面放两个成员变量,放个int型变量,和char型变量,然后在int变量的空间里面存入数字1,再通过char类型去访问它的第一个字节的空间,通过大小端字节序的概念(前面数据的存储的文章中有大小端字节序的介绍)可知:若该空间的值为1说明是小端存储,若为0说明是大端存储,
代码答案:
#include <stdio.h> union P { int a; char b; }; int main() { union P ss;//创建联合体变量 ss.a = 1;//给联合体的第一个成员赋值为1 if (ss.b == 1)//ss.b访问联合体的第二个成员 { printf("小端字节序存储\n"); } else { printf("大端字节序存储\n"); } return 0; }
解析:
说到这里基础薄弱的老铁或许会有很多疑惑,那么不着急,接下来我来带大家进行画图细致说明: