男女直接做网站,百度的首页,设计师招聘网站有哪些,商丘seo优化文章目录 1.结构体1.1什么是结构体1.2结构体类型声明1.3结构体变量的定义和初始化1.4结构体的访问 2.结构体对齐2.1如何对齐2.2为什么存在内存对齐#xff1f; 3.结构体实现位段3.1什么是位段3.2位段的内存分配3.3位段的跨平台问题3.4位段的应用3.5位段使用注意事项 4.联合体4… 文章目录 1.结构体1.1什么是结构体1.2结构体类型声明1.3结构体变量的定义和初始化1.4结构体的访问 2.结构体对齐2.1如何对齐2.2为什么存在内存对齐 3.结构体实现位段3.1什么是位段3.2位段的内存分配3.3位段的跨平台问题3.4位段的应用3.5位段使用注意事项 4.联合体4.1联合体的声明4.2联合体的特点4.3联合体的大小4.4联合体与结构体的对比 5.枚举5.1枚举类型的声明5.2枚举类型的优点 1.结构体
1.1什么是结构体
C语言已经提供了内置类型如char、short、int、long、float、double等但是只有这些内置类型还是不够的假设我想描述学生描述⼀本书这时单⼀的内置类型是不⾏的。描述⼀个学生需要名字、年龄、学号、身高、体重等描述⼀本书需要作者、出版社、定价等。C语言为了解决这个问题增加了结构体这种⾃定义的数据类型让程序员可以⾃⼰创造适合的类型。结构体是⼀些值的集合这些值称为成员变量。结构体的每个成员可以是不同类型的变量如标量、数组、指针甚⾄是其他结构体。
1.2结构体类型声明
关键字struct
struct stu //stu 结构体的名字
{//以下是结构体的成员变量int age;char name[20];float score;//......
}; //分号不能丢特殊声明方式匿名结构体即在声明结构体时不完全声明省略了结构体的名字。
struct
{int a;char b;float c;
}x;看下面的代码这样做的结果时什么
struct
{int a;char b;float c;
}x;
struct
{int a;char b;float c;
}a[20], * p;int main()
{p x;return 0;
}编译器会把上⾯的两个声明当成完全不同的两个类型所以是非法的。 匿名的结构体类型如果没有对结构体类型重命名的话基本上只能使⽤⼀次。
1.3结构体变量的定义和初始化
变量的定义
struct Point
{int x;int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2变量的初始化
struct Point p3 { 10, 20 };
struct Stu //类型声明
{char name[15];//名字int age; //年龄
};
struct Stu s1 { zhangsan, 20 };//按顺序初始化
struct Stu s2 { .age 20, .name lisi };//指定顺序初始化结构体嵌套、自引用
struct Node
{int data;struct Point p;//嵌套struct Node* next;//自引用
}n1 { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 { 20, {5, 6}, NULL };//结构体嵌套初始化1.4结构体的访问
结构体的访问有两种方式
直接访问通过点操作符.访问间接访问通过结构体指针访问访问方式结构体指针 - 成员名 2.结构体对齐
在下面的代码中char占1个字节int占4个字节那结构体的总大小就是5个字节真的是这样嘛
int main()
{struct s{char c;int i;};printf(%d\n, sizeof(struct s));return 0;
}2.1如何对齐
要弄清结果为什么是8我们就得了解结构体的对齐规则。 1.结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处 2.其他成员变量要对齐到某个数字对齐数的整数倍的地址处。 对齐数 编译器默认的⼀个对齐数 与 该成员变量大小的较小值。 3.VS 中默认的值为 8 4.Linux中 gcc 没有默认对齐数对齐数就是成员自身的大小。 5.如果嵌套了结构体的情况嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处 6.结构体的整体大小就是所有最大对齐数含嵌套结构体中成员的对齐数的整数倍
#pragma这个预处理指令可以修改编译器的默认对齐数
#pragma pack(1)//设置默认对⻬数为1
struct S
{char c1;int i;char c2;
};
#pragma pack()//取消设置的对⻬数还原为默认到底是怎么对齐的呢看下图 来练习几个吧 2.2为什么存在内存对齐
大部分的参考资料都是这样说的
平台原因 (移植原因) 不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取某些特定类型的数据否则抛出硬件异常。性能原因 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于为了访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数那么就可以⽤⼀个内存操作来读或者写值了。否则我们可能需要执行两次内存访问因为对象可能被分放在两个8字节内存块中。
总体来说结构体的内存对⻬是拿空间来换取时间的做法。 因此设计结构体的时候我们既要满足对齐⼜要节省空间就要让占用空间小的成员尽量集中在⼀起。
3.结构体实现位段
3.1什么是位段
你听说过位段吗是不是只听说过段位呀哈哈 位段的声明和结构是类似的有两个不同 位段的成员必须是 int、unsigned int 或signed int 在C99中位段成员的类型也可以 选择其他类型,例如char。位段的成员名后边有⼀个冒号和⼀个数字。 位段的位其实指的就是二进制位下面的A就是位段类型的
struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};
int main()
{printf(%d\n, sizeof(struct A));return 0;
}25103047bit一个字节是8个bit,那是不是6个字节就够了呢 结果是8个字节。为什么是8个字节呢----那是因为位段也存在对齐位段的总大小也要对齐到自己最大成员变量的整数被。 注意位段后的数字不可大于该数字本身的大小否则就报错
3.2位段的内存分配
关于位段在内存中是如何存储的C语言标准并未给出定义下面我们就研究以下在VS中位段是如何存储的。
struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};
int main()
{struct S s { 0 };s.a 10;s.b 12;s.c 3;s.d 4;return 0;
}我们假设如果第一个字节中放不下了就放在下一个字节中第一个字节中剩余的比特位就舍弃那么就是下面的结果 vs中是不是这样存储的呢看图我们知道确实就是这样存的。
3.3位段的跨平台问题
int 位段被当成有符号数还是⽆符号数是不确定的。位段中最⼤位的数⽬不能确定。16位机器最⼤1632位机器最⼤32写成27在16位机器会出问题。位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义。当⼀个结构包含两个位段第⼆个位段成员⽐较⼤⽆法容纳于第⼀个位段剩余的位时是舍弃剩余的位还是利用这是不确定的。
因此跟结构相比位段可以达到同样的效果并且可以很好的节省空间但是有跨平台的问题存在。
3.4位段的应用
下图是网络协议中IP数据报的格式我们可以看到其中很多的属性只需要⼏个bit位就能描述这⾥使⽤位段能够实现想要的效果也节省了空间这样⽹络传输的数据报大小也会较小⼀些对网络的畅通是有帮助的。
3.5位段使用注意事项
位段的⼏个成员共有同⼀个字节这样有些成员的起始位置并不是某个字节的起始位置那么这些位置处是没有地址的。内存中每个字节分配⼀个地址⼀个字节内部的bit位是没有地址的。所以不能对位段的成员使⽤操作符这样就不能使⽤scanf直接给位段的成员输⼊值只能是先输⼊放在⼀个变量中然后赋值给位段的成员。 4.联合体
4.1联合体的声明
像结构体⼀样联合体也是由⼀个或者多个成员构成这些成员可以是不同的类型。但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫共⽤体。给联合体其中⼀个成员赋值其他成员的值也跟着变化。 4.2联合体的特点
所有变量公用同一块空间改变一个成员其它成员跟着变 4.3联合体的大小
联合的大小⾄少是最⼤成员的大小。当最大成员大小不是最大对齐数的整数倍的时候就要对齐到最大对⻬数的整数倍。 4.4联合体与结构体的对比 因此使用联合体是比较节省空间的。
5.枚举
5.1枚举类型的声明
枚举枚举顾名思义就是一一列举。在生活中可以一 一列举出来的就可以使用枚举类型。例如 ⼀周的星期⼀到星期⽇是有限的7天可以⼀⼀列举 ⽉份有12个⽉也可以⼀⼀列举 … 枚举的关键字是enum枚举成员用逗号隔开最后一个成员不加逗号
枚举的可能取值是常量不能修改因此我们也叫做枚举常量枚举类型的变量的值只能是枚举的可能取值 enum day
{Monday, Tuesday, Wednsdsday 10, Thursday, Friday, Saturday 20, Sunday
};enum day d Sunday;//使⽤枚举常量给枚举变量赋值5.2枚举类型的优点
我们可以使用 #define 定义常量为什么非要使用枚举 枚举的优点 增加代码的可读性和可维护性和#define定义的标识符比较枚举有类型检查更加严谨。便于调试预处理阶段会删除 #define 定义的符号使用⽅便⼀次可以定义多个常量枚举常量是遵循作⽤域规则的枚举声明在函数内只能在函数内使⽤