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

网页游戏排行榜前十名3dseo外包如何

网页游戏排行榜前十名3d,seo外包如何,无代码开发小程序,软件公司介绍今天有个同事找到我,说发现了一个很神奇的问题,编译代码提示了未定义错误,但是明明包含了对应的头文件,而且查了好几遍,确认不存在包含错的问题,但就是编译失败,都怀疑是编译器 BUG 了&#xff…

今天有个同事找到我,说发现了一个很神奇的问题,编译代码提示了未定义错误,但是明明包含了对应的头文件,而且查了好几遍,确认不存在包含错的问题,但就是编译失败,都怀疑是编译器 BUG 了!

首先本着严谨的态度,不能说编译器不存在 BUG,但从实际角度来看,我们使用的编译器都是稳定发布版,而且用的都是最基本的功能,且未定义错误算是最基本的错误类型了,这种情况下出 BUG 的概率可以说微乎其微,所以还是让同事打开他的代码看一看。

不看不知道,一看 … 就很明了了!实际上这个问题很典型,很多老工程师在开发一些比较复杂的项目时如果稍不留神也会出现这种问题,不过只要你了解了问题的原因,下次再出现时就能很快定位到问题点并解决。

我们今天就来看看这到底是个啥问题!

首先我们准备几个代码文件,分别为 a.ca.hb.h

/** * a.c* 
**/#include <stdio.h>
#include "a.h"
#include "b.h"int main(void) {File1Struct file1;File2Struct file2;file1.data = 100;file1.ptr = &file2;  // 使用 b.h 中的结构体file2.ptr = NULL;    // 初始化指针printf("File1 data: %d\n", file1.data);return 0;
}
/** * a.h* 
**/#ifndef A_H
#define A_H#include "b.h"typedef struct _File1Struct {int data;File2Struct *ptr;
} File1Struct;#endif  // A_H
/** * b.h* 
**/#ifndef B_H
#define B_H#include "a.h"typedef struct _File2Struct {int value;File1Struct *ptr; 
} File2Struct;#endif  // B_H

代码很简单,我们也不急着分析,先编译一下看看:

jay@jaylinuxlenovo:~/test/code$ gcc a.c -o app
In file included from a.h:9,from a.c:7:
b.h:13:5: error: unknown type name ‘File1Struct’13 |     File1Struct *ptr;|     ^~~~~~~~~~~

可以看到编译报错了,报错位置是 b.h 的第 13 行,也就是下面这条代码:

File1Struct *ptr; 

而这条代码是包含在结构体 File2Struct 中的一个成员:

typedef struct _File2Struct {int value;File1Struct *ptr; 
} File2Struct;

错误信息的含义是 “未知的类型名 File1Struct”,根据一开始给出的代码文件,我们知道 File1Struct 是定义在 a.h 中的一个结构体:

typedef struct _File1Struct {int data;File2Struct *ptr;
} File1Struct;

所以第一个想到的就是没有包含 a.h 头文件,然而我们再回看 b.h 这个文件,明明是在开头就包含了 a.h:

/** * b.h* 
**/#ifndef B_H
#define B_H#include "a.h" //<----  这里明明包含了 a.htypedef struct _File2Struct {int value;File1Struct *ptr; 
} File2Struct;#endif  // B_H

明明包含了头文件,但却找不到头文件所包含头文件中定义的类型!你说奇不奇怪?如果你还没摸清其中的道道,那觉得奇怪是必然的,甚至有些朋友在自己的项目中遇到某个文件突然报这个错时会觉得其他的文件不会出现这种问题,就这个文件会出现这种问题,难道是玄学?

当然不是,一点都不玄,甚至可以说这是个非常低级的错误!

如果仔细观察 a.hb.h 这两个头文件,就会发现一个很别扭的现象,即 a.h 中定义的结构体里面其中一个成员是 b.h 中定义的结构体,而 b.h 定义的这个结构体中又包含了 a.h 中定义的结构体,导致 a.h 包含了 b.h,而 b.h 又包含了 a.h !这就是典型的循环依赖!

我们知道在编译的 预处理 阶段,头文件中的内容会被直接插入到引用它的源文件中,此时就有意思了,a.h 中的内容会被插入到源文件,但 a.h 中又包含了 b.h,此时 b.h 的内容同样也会被插入,而 b.h 又包含了 a.h,这时候又开始插入 a.h 的内容,如此循环,无穷无尽,整个编译过程就会在预处理阶段进入死循环。

当然我们在编写头文件的时候都有个规则,就是要用如下代码包裹实际内容:

#ifndef XXX
#define XXX// 文件内容#endif  

这段代码就是用于避免循环依赖进入死循环情况的,其原理也很简单,就是告诉预处理器在插入过 XXX 后如果遇到同样的内容就不再插入,这样在插入了 a.hb.h 后就不会再插入 a.h 了。然而这个问题解决了,我们的主要问题就很显现出来了。此时按照这个逻辑,在预处理后我们的 a.c 就会变成下面这样(实际会有更多内容,这里只保留我们关心的):

/** * a.c* 
**/// 省略 stdio.h 的内容 ......typedef struct _File2Struct {int value;File1Struct *ptr; 
} File2Struct;typedef struct _File1Struct {int data;File2Struct *ptr;
} File1Struct;int main(void) {File1Struct file1;File2Struct file2;file1.data = 100;file1.ptr = &file2;  // 使用 b.h 中的结构体file2.ptr = NULL;    // 初始化指针printf("File1 data: %d\n", file1.data);return 0;
}

很明显,File2Struct 定义在了 File1Struct 之前,自然在编译器解析 File2Struct 的成员类型 File1Struct 时它就是没有被定义过,当然这个与包含头文件的顺序有关,不同的顺序也会导致出现 File1Struct 定义在 File2Struct 之前的情况,此时就会报 File2Struct 未定义错误。

当把文件内容展开时这个问题变得显而易见,但大多数时候这种问题都是在一些比较复杂的工程结构下,动辄几十甚至上百的文件,且刚编写的时候大概率不会有问题,但往往在后期维护过程中修修补补,由于需求的增加需要在某个模块中加入另一个模块的接口,此时一不留神加了个会导致循环依赖的头文件,进而出现编译报警,此时所有文件自身内容实际都是没问题的,如果不特别留神头文件的包含关系,你就很难发现错误的原因!

问题找到了,怎么解决?

1 抽取公共内容到一个公共头文件

这种方法很好理解,既然 a 要用到 b 的内容,b 要用到 a 的内容,那我就搞一个 c,把 a 和 b 都需要的内容写到 c 中,然后 a 和 b 都包含 c 就行了,这种方式从源头就杜绝了循环依赖的出现,优化了代码的结构设计,也是最推荐的方式。

那如果我就是想要 a 包含 b,b 包含 a,还想要能编译成功,可行吗?

也可行!

2 使用前向声明

前向声明(Forward Declaration)是指在代码中仅声明某个类型或结构的存在,而不提供完整的定义。它允许代码引用某个类型(如结构体、类或函数),但推迟对其具体内容的定义。

基于这种方式,编译器就能在没有获取到某个类型的具体定义情况下先不进行报错,只要后续能找到具体的定义,编译就能成功:

/*** b.h***/#ifndef B_H
#define B_H#include "a.h"typedef struct _File1Struct File1Struct;  // 前向声明typedef struct _File2Struct {int value;File1Struct *ptr;
} File2Struct;#endif  // B_H

此时我们再尝试编译:

jay@jaylinuxlenovo:~/test/code$ make
gcc -c a.c
gcc -o app a.o 
jay@jaylinuxlenovo:~/test/code$ ./app 
File1 data: 100
jay@jaylinuxlenovo:~/test/code$ 

可以看到编译没有错误,最终程序也能正常运行,问题得到了解决。

最后还是要强调一下,虽然前向声明可以解决我们的问题,也可以精简代码与文件量,但一个稳定的系统一定是从设计层面就避免了类似的情况发生,而不是在发生后再通过某种方式进行补救。

http://www.dtcms.com/wzjs/187726.html

相关文章:

  • 建设网站的网站外贸怎么建立自己的网站
  • 桂城网站设计做公司网站
  • 广西造建设工程协会网站免费企业建站
  • 网站建设 的介绍5118数据分析平台官网
  • 做网站用什么程序品牌宣传
  • wordpress自适应网站博客模板最新天津百度网站快速排名
  • 做微商网站设计网站营销策略有哪些
  • 建设部精神文明建设网站网络优化工程师工作内容
  • 做网站买了域名后市场营销比较好写的论文题目
  • 成都网站建设小程序百度排行
  • 渠道建设网站app拉新推广赚佣金
  • 开发公司综合部内部管理章程杭州seo网站优化
  • 俄罗斯免费网站推广seo站内优化最主要的是什么
  • 做中学数学教案有哪些好的网站西seo优化排名
  • 南山网站建设公司全网万能搜索引擎
  • 任何查询网站有没有做404百度搜索智能精选
  • 电子商务网站建设 论文seo怎么才能做好
  • 网站建设工作推进会上的讲话哪有免费的网站
  • 邢台地区网站建设搜索关键词然后排名怎样提升
  • 广州做网站基本流程网站关键词排名seo
  • 盐城市网站最佳的资源磁力搜索引擎
  • 一个企业做网站的目的软文推广广告公司
  • 网站域名信息百度可以发布广告吗
  • 有域名后续怎么做网站百度推广天津总代理
  • 做黑彩网站赚钱吗谷歌google play官网下载
  • 做水果为主的b2c网站有哪些5000人朋友圈推广多少钱
  • 华为网络服务商江西seo推广方案
  • 专业微信网站开发公司输入关键词进行搜索
  • 企业网站建设的意义seo优缺点
  • 网站cms系统排名百度快照收录