C语言头文件和源文件差异,#include两种引用方式差异

一些初学c语言的人,不知道头文件(*.h文件)原来还可以自己写的。只知道调用系统库函数时,要使用#include语句将某些头文件包含进去。其实,头文件跟.c文件一样,是可以自己写的。头文件是一种文本文件,使用文本编辑器将代码编写好之后,以扩展名.h保存就行了。

头文件中一般放一些重复使用的代码,例如函数声明,变量声明,常数定义,宏的定义等等。当使用#include语句将头文件引用时,相当于将头文件中所有内容,复制到#include处。为了避免因为重复引用而导致的编译错误,头文件常具有:

#ifndef _delay_h_

#define _delay_h_

//代码部分

#endif

的格式。

其中,delay为一个唯一的标号,命名规则跟变量的命名规则一样。常根据它所在的头文件名来命名,例如,如果头文件的文件名叫做stc15w.h,那么可以这样使用:

#ifndef _stc15w_h_

#define _stc15w_h_

//代码部分

#endif

这样写的意思就是:如果没有定义__stc15w_h__,则定义__stc15w_h__,并编译下面的代码部分,直到遇到#endif。这样,当重复引用时,由于__stc15w_h__已经被定义,则下面的代码部分就不会被编译了,这样就避免了重复定义。

1、使用#include时,使用引号“”与尖括号<>的意思是不一样的。

使用引号“”时,编译器先搜索用户工程文件所在目录的头文件,再搜索系统默认目录的头文件;

使用尖括号< >时,先系统默认目录头文件,再用户文件目录的头文件,刚好是相反的搜索顺序,。

创建一个包含main的源文件,源文件里面包含函数的调用
# include<头文件> 编译器只会从系统默认配置的库环境中寻找头文件,不会搜索当前文件夹,通常用于引用标准库头文件
# include"头文件" 编译器会从当前文件夹中寻找头文件,如果找不到则到系统默认的库环境中寻找,一般用于引用用户自己定义使用的头文件

假设我们有两个文件名一样的头文件stc15w.h,但内容却是不一样的。一个保存在编译器指定的头文件目录下,我们把它叫做文件i;另一个则保存在当前工程的目录下,我们把它叫做文件ii。如果我们使用的是#include ,则我们引用到的是文件i。如果我们使用的是#include “stc15w.h”,则我们引用的将是文件ii。

相关资源:单片机C语言--头文件的编写_51单片机头文件怎么写-单片机文档类...

头文件和源文件在本质上没有任何区别。

后缀为 .h 的文件是头文件,内含函数声明、变量声明、类声明、宏定义、结构体定义等内容。

后缀为 .c 的文件是源文件,内含函数实现,变量定义等内容

而且是什么后缀也没有关系,只不过编译器会默认对某些后缀的文件采取某些动作。这样分开写成两个文件是一个良好的编程风格。
简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程:
  ①预处理阶段
  ②词法与语法分析阶段
  ③ 编译阶段,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各 个目标文件 (.obj文件)
  ④连接阶段,将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关 的可执行文件,当然,最后还可以用objcopy生成纯二进制码,也就是去掉了文件格 式信 息。(生成.exe文件)
  3.比方说 在aaa.h里定义了一个函数的声明,然后在aaa.h的同一个目录下建立aaa.c , aaa.c里定义了这个函数的实现,然后是在main函数所在.c文件里#include这个aaa.h 然后我就可以使用这个函数了。 main在运行时就会找到这个定义了这个函数的aaa.c文件。这是因为:main函数为标准C/C++的程序入口,编译器会先找到该函数所在的文件。假定编译程序编译myproj.c(其中含main())时,发现它include了mylib.h(其中声明了函数void test()),那么此时编译器将按照事先设定的路径(Include路径列表及代码文件所在的路径)查找与之同名的实现文件(扩展名为.cpp或.c,此例中为mylib.c),如果找到该文件,并在其中找到该函数(此例中为void test())的实现代码,则继续编译;如果在指定目录找不到实现文件,或者在该文件及后续的各include文件中未找到实现代码,则返回一个编译错误.

其实include的过程完全可以“看成”是一个文件拼接的过程,将声明和实现分别写在头文件及C文件中,或者将二者同时写在头文件中,理论上没有本质的区别。以上是所谓动态方式。对于静态方式,基本所有的C/C++编译器都支持一种链接方式被称为Static Link,即所谓静态链接。在这种方式下,我们所要做的,就是写出包含函数,类等等声明的头文件(a.h,b.h,...),以及他们对应的实现文件(a.cpp,b.cpp,...),编译程序会将其编译为静态的库文件(a.lib,b.lib,...)。在随后的代码重用过程中,我们只需要提供相应的头文件(.h)和相应的库文件(.lib),就可以使用过去的代码了。相对动态方式而言,静态方式的好处是实现代码的隐蔽性,即C++中提倡的“接口对外,实现代码不可见”。有利于库文件的转发 。

2、那么头文件是如何关联源文件的呢?

这个问题实际上是说,已知头文件“a.h”声明了一系列函数,“b.cpp”中实现了这些函数,那么如果我想在“c.cpp”中使用“a.h”中声明的这些在“b.cpp”中实现的函数,通常都是在“c.cpp”中使用#include “a.h”,那么c.cpp是怎样找到b.cpp中的实现呢?
谭浩强老师的《C程序设计》一书中提到,编译器预处理时,要对#include命令进行“文件包含处理”:将file2.c的全部内容复制到#include “file2.c”处。

这也正说明了,为什么很多编译器并不care到底这个文件的后缀名是什么,

因为#include预处理就是完成了一个“复制并插入代码”的工作
编译的时候,并不会去找b.cpp文件中的函数实现,只有在link的时候才进行这个工作。

这时如果我们明明的"b.cpp"如果与"a.h"同名的话,可以直接link上,即a与b名字相同,要不然就需要在b.cpp中# include a.h 就可以实现。

原文链接:https://blog.csdn.net/jq_98/article/details/124925526

C语言 #pragma once - C语言零基础入门教程_猿说编程的博客-CSDN博客

  • 8
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学海无涯_come on

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值