首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么这些头文件只能在预编译头文件之外工作?

头文件是C/C++程序中用于包含函数、变量、宏定义等声明的文件。预编译头文件是在编译过程中提前编译的头文件,以加快编译速度和优化代码。

在C/C++程序中,头文件通常通过#include指令包含到源代码中。头文件的作用是将声明和定义分离,使得代码更加模块化和可维护。预编译头文件则是为了提高编译效率,将一些常用的头文件预先编译好,以便在编译过程中直接使用。

然而,并不是所有的头文件都适合作为预编译头文件。这是因为预编译头文件在编译过程中只会被编译一次,然后被多个源文件共享使用。因此,只有那些不依赖于源文件特定内容的头文件才适合作为预编译头文件。

对于那些依赖于源文件特定内容的头文件,例如包含了某个源文件中定义的全局变量或宏定义的头文件,就不能作为预编译头文件使用。因为这些头文件的内容会根据不同的源文件而有所变化,无法被多个源文件共享使用。

因此,这些头文件只能在预编译头文件之外工作,即在每个源文件中单独包含。这样每个源文件都可以根据自己的需要包含相应的头文件,确保编译时能正确地解析和使用其中的声明和定义。

总结起来,预编译头文件适合包含那些不依赖于源文件特定内容的声明和定义,而那些依赖于源文件特定内容的头文件需要在每个源文件中单独包含。这样可以保证代码的正确性和可维护性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

Makefile-修改了.h头文件编译为什么不起作用?

不知道各位小伙伴是否碰到过这样的情况: 一个 .c 文件 include 另一个 .h 头文件,使用 Makefile 来构建(编译)应用程序。 第一次编译、执行,很正常!...但是此时,如果修改了 .h 头文件,再次编译时,就出现问题了: 预期的执行流程是:make 发现 .h 头文件的修改时间更新,于是重新编译包含这个头文件的所有 .c 文件。...可实际的结果却是:make 并没有识别出 .h 头文件的修改。 这是怎么回事呢?让我们一一道来。...: $ make gcc -o main main.o 可以看到:make 执行了 Makefile 中的链接指令(从目标文件 main.o 到可执行文件 main),并没有执行 gcc main.c...也就说明:make 并没有识别出 hello.h 这个头文件已经被改动了,尽管它“应该”可以从文件的修改时间上发现! 为什么会这样?

4.4K30

Objective-C中的预处理器指令与宏

预处理器是在OC源文件编译过程中的一个部分,而且是第一个处理部分,预处理器的也由此可见。...整个编译过程可以大致分为:预处理器进行词法分析 -> 语法分析 -> 生成代码和优化 -> 生成可执行的二进制文件。 既然有这么多过程,为什么要关注预处理器呢?...而对于#include和#import这两者,区别在于#import可以确保头文件被引用一次,这样就可以防止递归包含,什么叫递归包含,A引用B和C,B也引用了C,那就都包含了C,这就重复包含了。...除此之外,#pragma指令还包含很多别的选项,上面的是用的最多的,其他的可以查看文档。...结 以上就是OC编译中的预处理器中的一些预处理语言函数的内容,预处理器的内容当然不单单只有这些,还有对源文件的一些处理,但这些是我们平常开发中经常遇到的,了解他们是必须且重要的。 查看作者首页

68030

Qt高级编码约定

*/ static int y = 7; /* 正常工作: y将在编译期设置。*/ static MyStruct s = {1, 2, 3}; /* 正常工作: 编译期静态初始化。...这些符号没有被导出(大部分是内联的),会导致报符号冲突的编译错误提示。...向后二进制兼容性:链接到库的早期版本的代码保持正常工作。 向前的二进制兼容性:链接到新版本库的代码可与旧库一起使用。 源代码兼容性:代码无需修改即可编译。...*/ 如果operator ==在类之外,则转换规则将同样适用于双方。总结:范围小的值不能在前operator==使用。 公共头文件的约定 我们的公共头文件必须在某些用户的严格设置下仍然有效。...std::generate(begin, end, &Foo::someStaticFunction); ... } 为什么会出现这一规定(不能在lambda中使用类中的静态函数)?

1.7K30

C++ 温习笔记(1) - main函数,类对象,作用域,防止头文件二次编译

使用register变量是有限制的:(1) 不可能得到或计算register 变量的地址; (2) register变量只能在一个块中声明(不可能有全局的或静态的register变量)。...初始化在函数第一次调用时执行,函数调用之间变量的值保持不变,这种方式,函数可以“记住”函数调用之间的一些信息片断。...这也就是所谓的静态局部变量,具有局部作用域,它被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量在定义自己的函数体内始终可见...我们可能奇怪为什么不使用全局变量。static局部变量的优点是在函数范围之外它是不可用的,所以它不可能被轻易改变。这会使错误局部化。...(5) 外部变量 extern告诉编译器存在着一个变量和函数,即使编译器在当前的文件中没有看到它。这个变量或函数可能在一个文件或者在当前文件的后面定义。

1K10

程序员C语言快速上手——进阶篇(八)

在源文件中定义函数,那么在函数之外的地方,就属于全局作用域,即使是多个源文件,只要在函数之外,那它们就都属于全局作用域,全局作用域,全局都可访问。而在函数之内的空间声明变量,那它属于局部作用域。...全局变量 与局部变量相对的概念是全局变量,它声明在所有的函数体之外。...一旦函数同名了,就会形成命名冲突,这就是为什么我们看一些C语言编写的开源库时,变量名、函数命名非常的复杂,名字很长,多个单词大写或以下划线分隔,这样怪异的命名很大程度上就是为了避免命名冲突。...模块化开发的补充 头文件的嵌套包含 所谓嵌套包含,就是指在一个头文件中,还可以使用#include预编译指令,包含其他的头文件。...头文件include了两次,显然违背了我们上面说的,不能在一个源文件中将同一个头文件包含两次的原则。

91330

4 种预编译头文件(PCH)削弱代码的方式

如果使用得当,预编译头文件可以为您节省宝贵的编译时间。但如果使用不当,预编译头文件可能会隐藏源代码中的问题,而这些问题可能会在你尝试在另一个项目中重复使用部分源代码时才被发现。...预编译头文件的用途 发明预编译头文件的目的只有一个:"加快编译速度"。与反复解析相同的头文件相比,这些文件只需提前解析一次。速度非常重要!...对于预编译头文件来说也很方便。事实上,每个源文件都包含这些编译头文件,这也是前缀头文件的一个特点。 这就是事情开始出错的地方.........目的从 "尽可能快地编译这个项目 "转变为 "节省自己的打字时间"。Stack Overflow 的一个问题就反映了这一点,它问道:"为什么有重复的#import?...项目越大,做第一遍修复工作所需的时间就越长。如果您觉得累了,可以把它放在一边,稍后再继续清理。但我还是希望你能把项目清理干净。明确依赖关系是减少依赖关系的重要第一步。

14010

头文件】对.h文件的理解

头文件的概念 1.1 头文件的由来 在编译认识.c(.cpp)文件的年代,人们发现很多.c(.cpp)文件中的声明语句是相同的,但需要重复地敲入每个文件中,导致维护困难。...为了解决这个问题,人们将重复的部分提取出来放在一个新文件中,即“头文件”,通常使用.h扩展名。这些头文件包含了变量和函数的全局性声明,被其他.c文件共享,方便修改和维护大型代码。...因此,头文件中通常包含声明而很少包含具体实现的代码。...1.3 在.h文件中实现函数也不会出错的原因 要解决上述问题,首先必须弄清编译器的工作原理。编译器的最终目的是将程序员编写的源代码转换成机器能够识别运行的二进制机器码。...大体可分成 4 个步骤: 头文件的预编译,预处理 编译器在编译源代码时,会先编译头文件,保证每个头文件编译一次。 在预处理阶段,编译器将c文件中引用的头文件中的内容全部写到c文件中。

19610

Google C++编程风格指南(一)之头文件的相关规范

#endif // FOO_BAR_BAZ_H 2.1.2 #pragma once保护 #pragma once是编译指导指令,放在头文件的最开始位置,可以达到和条件宏一样的效果,即当头文件被重复包含时编译一次...,可依赖接口头文件,因为接口类是只有纯虚函数的抽象类,没有数据成员[3]^{[3]}。...I指定项目相对于编译工作目录的相对路径或者绝对路径。...即上面在使用g++编译的时候使用-Isrc来指明相对于编译工作目录的搜索目录。 还有一个需知就是:使用include包含头文件,使用相对路径时,相对的目录是编译器的工作目录。...、有条理; (4)包含文件的次序除了美观之外,最重要的是可以减少隐藏依赖,使每个头文件在“最需要编译”(对应源文件处)的地方编译,有人提出库文件放在最后,返样出错先是项目内的文件,头文件都放在对应源文件的最前面

2.8K10

一款可让大型iOS工程编译速度提升50%的工具

交付平台)的主流解决方案,但在某些场景下(Profile、Address/Thread/UB/Coverage Sanitizer、App 级别静态检查、ObjC 方法调用兼容性检查等等),我们的构建工作还是需要以全源码编译的方式进行...基于路径顺序查找头文件的方式存在潜在的风险,例如重名头文件的情况,排在后面的头文件永远无法参与编译。...还好 cocoapods-hmap-prebuilt 的出现,让这些问题变成了历史,不过要想理解它为什么能解决这些问题,我们得先理解一下什么是 Header Map。...通过上面的图,我们可以看到编译器将寻找头文件的顺序和对应路径展示出来了,而在这些路径中,我们看到了一些陌生的东西,即后缀名为 .hmap 的文件,后面还有个括号写着 headermap。 没错!...为什么用原生的 hmap 不能改善编译速度?

1.1K20

C++の命名空间namespace

命名空间是1995年引入标准C++(ANSIC++)中的, 那么为什么要引入这么一个概念呢?...形象点儿讲,namespace就像工程中的栅栏,把相关的代码(类,对象,函数,变量...)圈起来,这些namesapce 圈圈就相互独立,互不影响,各玩各的。画风就像下面: ?...除此之外,上面还有个匿名命名空间的例子,那么这个有什么用呢?...,但是这个命名空间对全局是不可见的,在当前文件中有用,而有名字的命名空间对全局是可见的,全局有效。...这个特点有点像static关键字,被static加持的全局变量,也只能在当前文件中有效。实际上匿名命名空间就是C++用来替代static的,C++新标准推荐使用匿名空间而不推荐static。

95720

C ++ 中不容忽视的 25 个 API 错误设计!

另外: 头文件的使用者不可能撤消命名空间包含,因此他们被迫使用决策来使用你的命名空间,这是不可取的。 它极大地增加了命名空间首先要解决的冲突的可能性。 当引入新版本的库时,程序的工作版本可能无法编译。...为什么这是一个错误? 如果该构造函数不破坏其强大的异常安全保证,则STL容器只能在其调整大小操作中使用移动构造函数。...错误#14:不避免不必要的include头文件 为什么这是一个错误? 不必要的头文件可以明显增加编译时间。...另外,很有意思的是,拥有独立的规模庞大的头文件会拖累构建并行化系统(如Incredibuild和FastBuild)的有效性。 如何解决这个问题? 你的API应该包含它绝对需要编译头文件。...利用testMain.cpp通过隔离编译方式来检查头文件内容,testMain.cpp除了包含测试的头文件之外什么也没有。如果它产生编译错误,那么需要将某些内容include在头文件中或向前声明。

1.5K20

借助 ChatGPT 编写的 libbpf eBPF 工具开发实践教程: 通过例子学习 eBPF

在BPF的可移植性和CO-RE一文中详细介绍了为什么会这样,以及为什么BCC是之前唯一的可行方式,此外还解释了为什么 libbpf 是目前比较好的选择。...除此之外,BCC使得用户在用户空间编写了大量样板代码,且需要手动配置最琐碎的部分。...如上所述,BCC依赖运行时编译,且本身嵌入了庞大的LLVM/Clang库,由于这些原因,BCC与理想的使用有一定差距: 编译时的高资源利用率(内存和CPU),在繁忙的服务器上时有可能干扰主流程。...依赖内核头文件包,不得不在每台目标主机上进行安装。即使这样,如果需要某些没有通过公共头文件暴露的内核内容时,需要将类型定义拷贝黏贴到BPF代码中,通过这种方式达成目的。...即使是很小的编译时错误也只能在运行时被检测到,之后不得不重新编译并重启用户层的应用;这大大影响了开发的迭代时间(并增加了挫败感…) Libbpf + BPF CO-RE (Compile Once –

1K20

C语言从入门到实战——预处理详解

例如,有些编译器可能支持非标准的 C 语言扩展,当编写需要兼容 ANSI C 的代码时,可以使用条件编译来控制是否使用这些扩展。...(a):(b)) 那为什么不用函数来完成这个任务? 原因有二: 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。...除了非常小的宏之外,程序的长度会大幅度增长 函数代码出现于一个地方;每次使用函数的时候,都会调用那个地方的同一个代码 执行速度 更快 存在函数的调用和返回的额外开销,所以会相对慢一些 操作符优先级 宏参数的求值是在所有周围表达式的上下文环境里...下面是一些常见的 #pragma 指令用法: #pragma once:用于确保头文件被包含一次,可以在头文件的开头使用该指令。...如果指定行号,则编译器将设置当前行号为指定的行号。如果指定文件名,则编译器将设置当前文件名为指定的文件名。如果同时指定行号和文件名,则编译器将设置当前行号和文件名为指定的值。

32511

加快C++代码的编译速度方法【转载】

可以想象,如果不加以重视,编译速度极有可能会成为开发过程中的一个瓶颈。那么,为什么C++它就编译的这么慢呢?...我想最重要的一个原因应该是C++基本的"头文件-源文件"的编译模型: 1.每个源文件作为一个编译单元,可能会包含上百甚至上千个头文件,而在每一个编译单元,这些头文件都会被从硬盘读进来一遍,然后被解析一遍...2.每个编译单元都会产生一个obj文件,然后所以这些obj文件会被link到一起,并且这个过程很难并行。 这里,问题在于无数头文件的重复load与解析,以及密集的磁盘操作。...2、Unity Build Unity Build做法很简单,把所有的cpp包含到一个cpp中(all.cpp) ,然后编译all.cpp。...这样我们就只有一个编译单元,这意味着不需要重复load与解析同一个头文件了,同时因为产生一个obj文件,在链接的时候也不需要那么密集的磁盘操作了,估计能有10x的提高,看看这个视频感受一下其做法与速度吧

3.1K20

技术◈C++核心知识总结(II)

命名空间是1995年引入标准C++(ANSIC++)中的, 那么为什么要引入这么一个概念呢?...形象点儿讲,namespace就像工程中的栅栏,把相关的代码(类,对象,函数,变量...)圈起来,这些namesapce 圈圈就相互独立,互不影响,各玩各的。画风就像下面: ?...除此之外,上面还有个匿名命名空间的例子,那么这个有什么用呢?...,但是这个命名空间对全局是不可见的,在当前文件中有用,而有名字的命名空间对全局是可见的,全局有效。...这个特点有点像static关键字,被static加持的全局变量,也只能在当前文件中有效。实际上匿名命名空间就是C++用来替代static的,C++新标准推荐使用匿名空间而不推荐static。

42830

C语言---头文件

今天说一个我在工作时候发现的一个细节,可能大家都已经清楚的知道了,我就在这里记录一下吧。 不想看过程的直接去文末看结论吧。 声明一下:以下源文件就是.c文件,头文件就是.h文件。...编程规范规定,头文件里面不能include其他文件,只能在源文件中include使用到的头文件,防止头文件重复包含。对于我这种平时没这个规范习惯的人来说,就有疑问了。...这样就可以正常使用了,如果头文件不包含头文件的话,在源文件中包含,这样能使用吗?会不会报错? 例如:源文件mian.c中包含了头文件a.h和b.h,头文件b.h中需要引用a.h中的数据结构类型。...去了解一下编译过程就知道了,在编译过程中有一个环节是预编译,就是来处理以"#"开始的预编译指令,其中对#include的处理规则如下: 处理 “#include” 预编译指令,将被包含的文件插入到该预编译指令的位置...由此可见,引入头文件跟我们定义变量差不多,要先定义然后才能在下面使用,这样就简单明了了。

4K20

BCC和libbpf的转换

在BPF的可移植性和CO-RE一文中详细介绍了为什么会这样,以及为什么BCC是之前唯一的可行方式,此外还解释了为什么 libbpf是目前比较好的选择。...除此之外,BCC使得用户在用户空间编写了大量样板代码,且需要手动配置最琐碎的部分。...如上所述,BCC依赖运行时编译,且本身嵌入了庞大的LLVM/Clang库,由于这些原因,BCC与理想的使用有一定差距: 编译时的高资源利用率(内存和CPU),在繁忙的服务器上时有可能干扰主流程。...即使是很小的编译时错误也只能在运行时被检测到,之后不得不重新编译并重启用户层的应用;这大大影响了开发的迭代时间(并增加了挫败感...)...本文解释了多种配置步骤,并概述了常见的模式,以及可能会碰到的不同点,困难和陷阱。

1.7K00

详细剖析 extern C

extern "C"的前世今生 在C++编译器里,有一位暗黑破坏神,专门从事一份称作“名字粉碎”(name mangling)的工作。...随后,我们想让一个C++程序调用这些函数,所以,它也包含了头文件my_handle.h。...拿之前的例子来说,如果我们把各个头文件的 #include 指令都移到extern "C" { } 之外,然后使用C++编译器的预处理选项来编译foo.cpp,就会得到下面的结果: 这样的结果肯定不会引起编译问题的结果...或许你会说,“我可以去查看这些被包含的头文件,我可以保证它们不会带来麻烦”。但,何必呢?毕竟,我们完全可以不必为不必要的事情买单,不是吗?...这些头文件和常规的头文件作用是不一样的,它们里面不会放置C的函数声明或者变量定义,链接规范不会对它们的内容产生影响。这种情况下,你可以不必遵守这些规则。

1.3K30

h文件和c文件的区别include本身只是一个简单的文件包含预处理命令,即为把include的后面文件放到这条命令这里,除此之外,没有其它的用处(至少我也样认为).

%d\n",test); } 头文件内容如下: 现在以这个例子来讲解编译器的工作: 1.预处理阶段:编译器以C文件作为一个单元,首先读这个C文件,发现第一句与第二句是包含一个头文件,就会在所有搜索路径中寻找这两个文件...,主要的工作就是重定位各个目标文件的函数,变量等,相当于将个目标文件中的二进制码按一定的规范合到一个文件中 再回到C文件与头文件各写什么内容的话题上: 理论上来说C文件与头文件里的内容,只要是C语言所支持的...头文件与之实现文件的的关系 关于两者以前的关系,要从N年以前说起了~ long long ago,once aupon a time .......那是一个被遗忘的年代,在编译认识.c(.cpp))...预处理是编译器的前驱,作用是把存储在不同文件里的程序模块集成为一个完整的源程序. include本身只是一个简单的文件包含预处理命令,即为把include的后面文件放到这条命令这里,除此之外,没有其它的用处...1.为什么经常见 xx.c 里面 include 对应的 xx.h? 2.如果 a.c 中不写,那么编译器是不是会自动把 .h 文件里面的东西跟同名的 .c 文件绑定在一起?

1.4K20
领券