C/C++的头文件 / 源文件 / 条件编译 / 多文件编译

头文件

头文件的定义与作用

之前我的博客讲了C/C++中声明(declaration)和定义(definition)的区别,让大家好区分一下这两个概念。其实不区分也行,把他们统称为定义都行。只不过今天要讲的头文件,他就是用来放声明用的(也有其他东西),比较少用来直接定义。

这里引用一下百度百科对头文件的定义:

在C语言家族程序中,头文件被大量使用。一般而言,每个C++/C程序通常由头文件和定义文件组成。头文件作为一种包含功能函数、数据接口声明的载体文件,主要用于保存程序的声明,而定义文件用于保存程序的实现。

C语言的头文件通常以.h或者.hpp作为后缀,像stdio.h(标准输入输出)或者是stdlib.h(标准库),都是我们入门C时比较常用的两个系统头文件。使用Linux系统的同学可以在/usr/include目录下找到这两个头文件:

ls /usr/include/std*
/usr/include/stdc-predef.h  /usr/include/stdint.h  /usr/include/stdio_ext.h  /usr/include/stdio.h  /usr/include/stdlib.h

用cat命令可以查看一下里面的内容,内容太多我在这就不放出来了。大体都是些条件编译,#define宏定义,还有一些函数的声明等等,没有具体的定义。他的作用主要有:

头文件的主要作用在于多个代码文件全局变量(函数)的重用、防止定义的冲突,对各个被调用函数给出一个描述,其本身不需要包含程序的逻辑实现代码,它只起描述性作用,用户程序只需要按照头文件中的接口声明来调用相关函数或变量,链接器会从库中寻找相应的实际定义代码。

#include编译指令

我们在学习写C语言代码的时候,都会在最前面写上#include <stdio.h>和#include <stdlib.h>表示包含这两个头文件,然后在代码中就可以使用printf、scanf、malloc、free等等一些列常用的功能函数。那么在这个过程中,编译器做了什么事情呢?

其实#include是一条编译的指令,他在编译阶段告诉编译器:我需要包含这个头文件。然后编译器就会去系统路径中找到对应的头文件,然后将其原封不动地复制到你的代码中,所以你就可以使用头文件中声明的函数了。

这里要说明的是#include <>和#include ""是有区别的。尖括号表示该头文件要去系统路径找,找不到的话就在当前路径下找;而双引号则表示直接在当前路径上找,经常用于包含用户自定义的头文件。

头文件实例

这里我们自己来写个头文件来包含一下,看看编译器是怎么出来#include指令的。这里为了演示我直接给出函数的定义了,然后随便写了点东西进去(真正在工程中是不推荐的)。编写一个头文件如下:

//my_header.h
double glob = 10;

void fun(){
   
	int a = 1;
	char b = 2;
}

然后写一个源文件来包含上面的头文件:

#include "my_header.h"

//test_header.c
int main(){
   
	return 0;
}

使用gcc进行编译,只激活预编译:

[dyamo@~/code 15:23]$ gcc -E test_header.c
# 1 "test_header.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "test_header.c"
# 1 "my_header.h" 1
double glob = 10;

void fun(){
   
 int a = 1;
 char b = 2;
}
# 2 "test_header.c" 2


int main(){
   
 return 0;
}

可以看到编译器做了一些处理。首先编译器会把注释先删除了,然后再把my_header.h文件的内容复制到test_header.c文件中。

源文件

既然头文件只是用来放声明的,那他的定义放在哪呢?源文件就是用来解决这个问题的。

我们在工程中通常将声明和定义分开放在头文件和源文件中,这样方便工程的模块化管理。源文件就是我们经常写的.c或者.cpp文件。可能刚刚入门C语言的同学没有太多的感触,因为刚刚学习的时候代码功能简单,不需要刻意去分模块。最多就是在main函数所在的文件多写几个函数来实现模块功能,不会特地去分什么头文件源文件。

其实除了方便模块化管理的原因外,还有一个更重要的原因导致了头文件和源文件必须分开来写,那就是避免重复定义。 上面也说了,编译器是直接将头文件复制到包含的地方的。如果在头文件里面定义了某个函数,然后另外一个头文件也定义一个同名的函数,然后一个main.c文件同时包含这两个头文件,就会出现相同函数在同一个地方被定义了两次,这明显是不被允许的,直接编译报错。

但是如果头文件里面只写声明不写定义,那么情况就不一样了。编译器不管你写了多少次声明,都能给你编译通过,最多给个编译警告,只要不重复定义产生二义性问题就行。然后再写个定义去实现函数功能,使用函数的时候也不会报段错误。

现在我们将上面写的my_header.h修改一下,用一个main.c文件来放fun函数的定义,并在main函数中调用:

//my_header.h
void fun();
//main.c
#include <stdio.h>
#include 
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在VSCode中进行C++多文件编译时,文件的关联是非常重要的。以下是一些基本的步骤来确保文件正确关联: 1. 在源文件中包含文件:在您的源文件(.cpp文件)中,使用`#include`指令来包含相关的文件。例如,如果您有一个名为`example.h`的文件,您可以在源文件中添加`#include "example.h"`来关联它。 2. 设置文件搜索路径:如果您的文件不在源文件所在的目录中,您需要设置文件的搜索路径。在VSCode中,可以通过编辑`.vscode/tasks.json`文件中的构建任务来设置编译器的搜索路径。在编译命令中使用`-I`选项来指定文件的路径。例如:`g++ -I/path/to/header-files main.cpp -o main` 3. 确保文件源文件同名:为了方便管理,通常将文件源文件命名相同,并使用`.h`和`.cpp`作为扩展名。这样可以更容易地找到和关联相应的文件源文件。 4. 使用预编译指令:如果您的文件用于定义常量、宏或模板类/函数等,您可能需要在使用它们的源文件中添加适当的预编译指令。例如,如果您在文件中定义了一个模板类,您需要在使用该类的源文件中添加`template class ClassName<Type>;`来实例化模板。 请注意,具体的步骤和配置可能因您的项目和开发环境而有所不同。您可能需要根据实际情况自定义构建任务和编译选项。 希望这些步骤能帮助您在VSCode中成功进行C++多文件编译并正确关联文件。如有任何问题,请随时向我提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值