当前位置: 首页 > news >正文

那个网址怎么找广州seo网站管理

那个网址怎么找,广州seo网站管理,长沙网站设计培训学校,安徽展览展示公司排名目录 1. 结构体 1.1. 结构体类型的声明 1.1.1. 特殊声明 2. 结构的自引用 3. 结构体变量的定义和初始化 4. 结构体内存对齐 4.1. 结构体内存对齐 4.2. 修改默认对齐数 5. 结构体传参 6. 结构体实现位段#xff08;位段的填充可移植性#xff09; 6.1. 什么是位…目录 1. 结构体 1.1. 结构体类型的声明 1.1.1. 特殊声明 2. 结构的自引用 3. 结构体变量的定义和初始化 4. 结构体内存对齐 4.1. 结构体内存对齐 4.2. 修改默认对齐数 5. 结构体传参 6. 结构体实现位段位段的填充可移植性 6.1. 什么是位段 6.2. 位段的内存分配  2. 枚举 2.1. 枚举 2.2. 枚举常量的优点 3. 联合 3.1. 联合 3.2. 判断大小端 3.3. 联合大小的计算 1. 结构体 首先为什么要求这些自定义类型呢在C语言中其标准已经为我们提供了许多的内置类型int、char、double等等但是有些情况下人们发现单单靠这些内置类型无法满足现实世界各种复杂的情况例如如果我们要描述一本书我们是不是应该描述它的书名、作者、出版社等等各种信息我们发现如果此时只有内置类型是不可能达成类似这种复杂需求的于是C赋予了程序员们一种权利可以定义自定义类型。而结构体就是自定义类型中的一种。 1.1. 结构体类型的声明 首先我们看看结构体的声明是怎样的呢 // 假如我要描述一本书 struct book {char book_name[20];char author_name[10];int book_pages;//... 各种信息 }; // 注意这里的 ; 不可漏掉 上面的struct book就是一个结构体类型的声明。 1.1.1. 特殊声明 在声明结构体类型时C标准允许可以不完全声明 struct {int x;int y;int z; }target; //并且此时只能在这里定义这个类型的变量struct {int x;int y;int z; }*p; // 定义了一个这个结构体类型指针的变量 上面的类型就是一个匿名结构体类型有人看到这两个匿名结构体的成员变量完全一样那能不能这样做呢 void Test1(void) {p x; } 首先这样做是不好的。编译器对于匿名结构体的处理是如果匿名结构体的成员变量一样编译器也认为它们是不同的类型。 2. 结构的自引用 结构体的自引用简单理解就是结构体类型中的成员变量包含一个结构体类型的指针变量。 struct Node {int val;struct Node next; }; 上面的代码可行吗 答案是不可行。为什么呢struct Node这个自定义类型中包含一个类型为struct Node的成员next而这个成员也是一个自定义类型struct Node那它里面也有一个struct Node类型的成员啊这种无穷包含自己在编译器看来是一种非法行为因为此时这个类型的大小无法确定。 正确的自引用是这样的  struct Node {int val;struct Node* next; }; 而我们直到typedef可以对一种数据类型进行重命名那么它可以对结构体类型重命名吗当然可以。例如如下 typedef struct Node {int val;struct Node* next; }Node; 上面的代码的意思是什么呢就是定义了一个struct Node的结构体类型我们对这个结构体类型重命名为 Node即 Node 等价于 struct Node它们代表着同一种类型。  然而有人看到这里就会突发奇想他说既然Node和 struct Node代表着同一种类型那么可不可以这样呢 typedef struct Node {int val;Node* next; }Node; // 走到这里才代表对struct Node进行重命名为 Node 首先说答案上面这种声明是非法的因为此时的这个成员变量next的类型还没有完成重命名也就是先有鸡还是先有蛋的问题只有走完这个类型重命名语句才会对struct Node进行重命名为 Node不可以在重命名之前就使用重命名后的类型。因此正确的命名是如下这种形式 typedef struct Node {int val;struct Node* next; }Node; 然而有时候我们会在书中看到这样的声明风格 typedef struct Node {int val;struct Node* next; }Node,*PNode; 其实很简单 这里的Node等价于struct Node PNode就相当于 struct Node* 3. 结构体变量的定义和初始化 struct Book {char book_name[20];int book_pages;double price; }b1 {XqianC语言,531,33.3}; // 声明 定义了一个struct Book类型的全局变量struct Node {struct Book b;struct Node* next; }n1 { {wangwuLinux,843,55.5},NULL }; // 定义一个结构体嵌套类型的全局变量void Test3(void) {struct Book b2; // 定义一个struct Book类型的局部变量// 给b2的成员变量赋值b2.book_name[20] lisiC;b2.book_pages 632;b2.price 44.4; // 定义 初始化struct Node n2 { { cuihuaMySql, 483, 66.6 }, NULL }; // 定义一个结构体嵌套类型的局部变量 } 4. 结构体内存对齐 4.1. 结构体内存对齐 首先我们看看下面的这两个类型 struct type1 {char ch1;int i;char ch2; };struct type2 {char ch1;char ch2;int i; }; 现在要求我们计算着两个类型分别是多大即 void Test4(void) {printf(struct type1 size %d\n, sizeof(struct type1));printf(struct type2 size %d\n, sizeof(struct type2)); } 有人一看这两个类型诶这两个类型的成员变量除了顺序不一样其他都是一样的啊让我算的话它们的大小难道不应该是 两个 char 一个 int类型的大小即等于6吗OK让我们看看它的结果是多少呢 出人意料诶怎么回事不是6就是算了怎么这两个类型的大小还不一样。为了解决这个问题我们要引出一个东西称之为结构体内存对齐规则。 那么结构体内存对齐规则是什么呢如下 1. 第一个成员在与结构体变量偏移量为0的地址处。 2. 其他成员变量要对齐到某个数字对齐数的整数倍的地址处。 对齐数 编译器默认的对齐数 与 该成员变量类型大小 的较小值 vs下默认对齐数为8 3. 结构体总大小为最大对齐数的整数倍。 最大对齐数所有成员变量类型大小中的最大值。 4. 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。 有了结构体内存对齐规则我们就可以分析上面这两个结构体类型的大小为何如此了分析如下 声明为了更好理解下面的图由于结构体对齐规则导致没有使用的空间用红色表示 对struct type1的分析如下  对struct type2的分析如下  有了对上面的理解我们试着去计算下面这个结构体类型的大小 struct type3 {char ch1struct type2 t2;char ch2;int i; }; 为了验证上面结构体成员的偏移量是否与预期正确我们可以用offsetof它是一个宏可以帮助我们计算一个结构体中某个成员变量相对于起始位置的偏移量。 // 原型如下 // 其包含在 #include stddef.h // structName --- 结构体名字 // memberName --- 成员变量名字 size_t offsetof( structName, memberName ); void Test5(void) {printf(ch1 offset: %d\n, offsetof(struct type3, ch1));printf(t2 offset: %d\n, offsetof(struct type3, t2));printf(ch2 offset: %d\n, offsetof(struct type3, ch2));printf(i offset: %d\n, offsetof(struct type3, i)); } 结果如下:  很显然符合我们的预期。 那么为什么要存在内存对齐 1. 平台原因(移植原因) 不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取某些特定类型的数据否则抛出硬件异常。 2. 性能原因 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于为了访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要一次访问。 总体来说结构体的内存对齐是拿空间来换取时间的做法。 那在设计结构体的时候如果我们既要满足对齐又要节省空间该如何做呢 答案是让占用空间小的结构体成员尽量集中在一起例如 struct type1 {char ch1;int i;char ch2; };struct type2 {char ch1;char ch2;int i; }; struct type1和struct type2的成员变量是一样的但是它们的大小确是不一样的前者占12个字节后者占8个字节原因就在于struct type2中的较小成员集中在了一起节省了一定的空间。 4.2. 修改默认对齐数 我们知道VS下的默认对齐数是8但是我们却可以显式的修改其默认对齐数。 // 编译器的默认对齐数为8 struct type5 { char ch; double d; }; #pragma pack(4) // 将编译器的对齐数修改为4 struct type5 {char ch;double d; }; #pragma pack() // 取消设置的对齐数,还原为默认对齐数 #pragma pack(1) // 将编译器的对齐数修改为1,就意味着不对齐.此时的大小就是9 struct type5 {char ch;double d; }; #pragma pack() // 取消设置的对齐数,还原为默认对齐数 结构体在对齐方式不合适的时候我们可以自己更改默认对齐数。   5. 结构体传参 struct Info {int data[1000];char* name[1000]; };// 结构体传参 void print1(struct Info tmp) {//... }// 结构体的地址传参 void print2(struct Info* p_tmp) {//... }void Test7(void) {struct Info information { { 1, 2, 3 }, {NULL} };print1(information); // 不推荐,值传递传参的压栈系统开销过大print2(information); // 推荐,址传递传参的压栈系统开销很小 } 对于结构体的传参我们推荐采用以传结构体地址的方式因为函数在传参的时候会将其参数压栈在时间上和空间上都会有消耗如果我们传递一个结构体对象当这个结构体很大的时候参数压栈的系统开销就会很大会导致性能的降低而如果传递一个结构体指针其大小是固定的(32位下4个字节、64位下8个字节)可以节省系统的开销一定程度上提高性能。 结论结构体传参尽量传结构体的地址。 6. 结构体实现位段位段的填充可移植性 6.1. 什么是位段 1. 位段的成员必须是 int 、 unsigned int 或 signed int或者char(char也是属于整形家族) 。 2. 位段的成员名后边有一个冒号和一个数字。 struct bit {int a : 2;int b : 5;int c : 10;int d : 30; }; 上面就是一个位段我们可以看到位段的成员后面有一个冒号和一个数字这个数字代表着你这个成员占用了几个bit位例如a这个成员就会占用2个bit位。那么位段的大小如何计算呢位段需要进行内存对齐吗 首先对于位段我们应该知道其主要作用是节省空间而我们知道结构体的内存对齐是以空间换取时间的一种方式很显然这就与位段的初衷相矛盾了故位段是不会有内存对齐的。 void Test8(void) {printf(bit size %d\n, sizeof(struct bit)); } 那么上面这个位段是多大呢 可以看到这个位段共占用了8个字节的确节省了空间。那么位段究竟是如何分配内存的呢 6.2. 位段的内存分配  1. 位段的成员可以是 int、unsigned int、 signed int、  或者是 char( 属于整形家族)类型 2. 位段的空间上是按照需要以 4 个字节 int 或者 1 个字节 char 的方式来开辟的。 3. 位段涉及很多不确定因素位段是不跨平台的注重可移植的程序应该避免使用位段 之所以说位段是不跨平台的是由于当出现上面这种情况时我们不知道它的内存分配是怎样的例如上面剩余了15个bit位d到底有没有使用它是不确定的标准并没有明确规定是否使用这个15个bit。因此对于位段的使用要小心如果要求程序具有移植性那么尽量减少位段的使用。 位段的跨平台问题 1. int 位段被当成有符号数还是无符号数是不确定的。 2. 位段中最大位的数目不能确定。16位机器最大1632位机器最大32写成27在16位机器会出问题。 3. 位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义(vs下是从右向左分配的)。 4. 当一个结构包含两个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是舍弃剩余的位还是利用这是不确定的(vs下没有利用剩余的空间) 总结 位段较结构体相比位段可以达到同样的效果但是可以很好的节省空间但由于标准对许多细节并没有明确规定存在跨平台的问题其可移植性是有待商榷。 2. 枚举 2.1. 枚举 枚举enum是一种用于定义一组相关常量的数据类型。它可以帮助开发人员更清晰地表示某个值的取值范围并提供更好的可读性和可维护性。 在枚举类型中我们可以定义一组具体的命名常量也称为枚举成员。每个枚举成员都有一个与之关联的值它可以是数字如整数或者是其他数据类型如字符串。枚举成员之间用逗号隔开。 使用枚举我们可以通过给定的枚举成员来表示某个特定的取值。这有助于编写更可读的代码并减少硬编码所带来的错误。此外枚举还可以作为函数参数、变量和属性的类型增加代码的类型安全性。 enum color {RED,YELLOW,BILU }; 上面的enum color 就是一种枚举类型{}中的内容是枚举类型的可能取值也称之为枚举常量这些枚举常量都是有值的默认从0开始依次递增1当然在定义的时候也可以赋初值例如 enum color {RED 5,YELLOW 3,BLACK, // 这里的BLACK没有赋初值,那么就是YELLOW 1,即等于4BILU 7 // 注意,最后一项的枚举常量不加, }; 2.2. 枚举常量的优点 为什么要使用枚举常量呢它与#define定义的符号常量有什么区别呢 枚举常量的优点 1. 增加代码的可读性和可维护性 2. 和 #define 定义的标识符比较枚举有类型检查更加严谨。 枚举常量是属于一种枚举类型的它是具有类型检查的与符号常量相比更为严谨 3. 防止了命名污染封装 4. 便于调试宏定义的符号常量在预编译阶段就被替换了。 5. 使用方便一次可以定义多个常量 因此我们推荐使用枚举常量以减少宏定义的标识符的使用 3. 联合 3.1. 联合 联合union是一种特殊的 自定义类型 它可用于在同一内存空间中存储不同的数据类型。它允许使用同一块内存来存储多种类型的数据但同一时间只能使用其中的一种类型数据。 联合与结构体非常相似都可以定义多个成员但联合只分配给它成员中最大的元素所需要的内存空间(需要考虑内存对齐,当最大成员的大小不是最大对齐数的整数倍时就需要内存对齐)。因此联合可以通过不同的成员来表示同一块内存中的数据这使得它在一定程度上可以节省内存空间。 联合体的特征就是联合的成员共用同一块空间所以联合也叫共用体示例如下 union Un {char ch;int i; }; 那么上面这个联合体的大小是多少呢 void Test10(void) {printf(Un size: %d\n, sizeof(union Un)); } 联合的大小是由其最大的成员决定的例如上面的这个联合其最大成员是一个int类型又因为此时这个联合体的最大对齐数就是4因此上面这个联合的大小就是4。  void Test11(void) {union Un u;printf(u address: %p\n, u);printf(ch address: %p\n, (u.ch));printf(i address: %p\n, (u.i)); } 可以发现联合对象和它的成员的地址是一样的也就是说其内存分配如图所示 联合的特定是成员共享同一块空间但这也限制了在同一时刻只可以使用一种成员。例如 union Un {char ch;int i; }; void Test12(void) {union Un u;u.i 0x11223344;u.ch 0x66; } 在使用联合时改变其中一个成员变量另一个成员变量也会被修改因此一般情况下联合在某一时刻下是单独使用一个成员变量的 。 3.2. 判断大小端 什么叫大端什么叫小端呢 大端Big Endian和小端Little Endian是用于描述存储和处理多字节数据的方式。 大端字节序Big Endian是指将最高有效字节Most Significant ByteMSB存储在最低地址处最低有效字节Least Significant ByteLSB存储在最高地址处。也就是说数据的高位字节存储在低位地址低位字节存储在高位地址。 小端字节序Little Endian则相反它是指将最低有效字节LSB存储在最低地址处最高有效字节MSB存储在最高地址处。也就是说数据的低位字节存储在低位地址高位字节存储在高位地址。 void Test13(void) {int i 0x12345678;// 对于0x12345678的大端字节序和小端字节序// 低地址 --------------- 高地址// 大端字节序:// 0x12 0x34 0x56 0x78// 小端字节序:// 0x78 0x56 0x34 0x12 } 利用联合的特性(其成员共有同一块空间)我们就可以判断某个机器下是大段还是小端存储那么如何判断呢 union Un {char ch;int i; };void Test14(void) {union Un u;u.i 1;// 此时如果u.ch 1,那么就是小端;如果u.ch 0,那么就是大端if (u.ch 1)printf(小端存储\n);if (u.ch 0)printf(大端存储\n); } 3.3. 联合大小的计算 union Un1 {char ch[5];int i; }; 上面的联合体是多大呢注意联合体的的大小首先是要保证能够存放最大成员其次如果最大成员所占空间大小不是其最大对齐数的整数倍那么需要内存对齐。例如上面的 至此C语言的自定义类型到此结束。
http://www.tj-hxxt.cn/news/139381.html

相关文章:

  • 中文电子商务网站模板河南省中原建设有限公司网站
  • 广州白云区做网站沙洋县seo优化排名价格
  • 大理网站建设沛宣建设网站入不入无形资产
  • 宜昌做网站微信服务号功能开发
  • 怎么做盗号网站门户网站系统建设项目招标书
  • 网站建设西班牙语关于网站建设的合同范本正规
  • 2014网站设计风格2023今天的新闻联播
  • 华夏名网网站建设教程wordpress网站管理系统
  • 网站的查询功能是怎样做的wordpress连接mysql8
  • 四川省城镇建设二次供水网站南京尔顺科技发展有限公司表扬信息网络公司网站报价
  • 西安市专业网站建设咨询型网站
  • 餐饮网站系统栾城区住房建设局官方网站
  • 定期更新网站外国人做的学汉字网站
  • 厦门外贸网站下载建行手机银行官方正式版
  • 南京网站seo网站建设的内容管理
  • 农场游戏系统开发 网站建设推广公司网站怎样维护运营
  • 做网站哪个部分网站建设案例价位
  • 校园门户网站建设网站如何添加白名单
  • 微信 网站设计模板做网站用什么云服务器
  • 大理网站建设沛宣企业注册app下载
  • 网站制作的内容什么好网站网页的书签怎么做
  • 如何让别人看到自己做的网站中国广告设计网站
  • 单位网站的作用重庆制作网站培训机构
  • 网站开发网站源码网络营销推广的要点
  • 克隆网站后台做一个网站多长时间
  • 网上做任务挣钱的网站咨询公司来公司做调查
  • 高端建站行业烟台做网站打电话话术
  • 做装修公司网站一起来看在线观看免费
  • 企业门户网站建设咨询桂林人论坛
  • 如何做游戏推广搜索引擎优化seo课程总结