预处理过程:头文件

本文学习编译器在预处理过程中对头文件的处理。Hightec编译器版本是tricore v4.9.1.0。博主在<基于模型的设计>板块就经常提到头文件,本文会从编译器的角度对头文件进行学习。

1 Include语法

头文件一般包含C语言的声明和宏定义。在C语言源文件中,通常在最上面用#include指令调用,俗称为包含某个头文件。

头文件一般分为系统头文件和用户头文件。

  • 系统头文件通常是用来调用系统库,在#include后面要用尖括号。
#include <file>
  • 用户头文件中通常是函数、全局变量的外部声明, 宏定义,结构体定义,类型定义等。用户头文件起到了一个接口的作用,将不同的独立C文件通过头文件联系起来。用户头文件在#include后面要用引号。
#include "file"

2 编译器对Include的处理

调用编译器对某个C源文件进行预处理时,如果编译器看到了#include指令,就会先扫描一下#include后的头文件,然后把头文件展开到#include指令的位置。

为了直观地体会到这个过程,可以自己创建一些文件,然后调用编译器进行预处理。

1)首先,创建一个 header.h 头文件如下;
在这里插入图片描述
在这个头文件中对test函数进行了外部声明。

2)然后再建立一个program.c文件,如下;
在这里插入图片描述
在C文件中显示定义了一个变量x,然后包含了header.h这个头文件,然后定义了test2函数。

3)通过如下命令行调用编译器,对当前目录下地 program.c 代码进行预处理。

tricore-gcc -E program.c -o program.i

在这里插入图片描述
4)在生成的.i文件中,可以看到 header.h 头文件的内容被插入到了 program.c 源文件中;
在这里插入图片描述
另外,头文件中也可以嵌套包含头文件,这样的话就会一层一层地展开。

3 头文件的搜索路径

上一章是把头文件和源文件放在了一个路径下,通过编译器进行预处理。如果不特别地指出,编译器会在几个安装路径下和当前路径搜索头文件。如果要指定搜索头文件的路径,可以用 -I 参数指明.

例如,把头文件放在inc文件夹中,如下:
在这里插入图片描述
这样的话,命令行就要写成下面的样子。

tricore-gcc -E program.c -o program.i -I ./inc

如果不加 -I 参数,编译器会报出找不到头文件的错误,如下图。
在这里插入图片描述
所以工作中如果看到了这种错误,就要考虑是头文件没加到路径中,还是路径没加到命令行中。

4 只加载一次头文件

4.1 问题

实际项目中会有大量地头文件嵌套,一不小心就会重复包含了头文件。重复包含头文件会有两个问题:一方面如果头文件中有结构体定义,在编译的阶段会报错(预处理过程是不会报错的);另一方面,就算没有重复定义的报错,重复加载也会浪费时间。

对于结构体重复定义的报错,可以自己复现出来。

1)首先把第2章中的头文件稍作修改,定义一个结构体。
在这里插入图片描述
2)然后在C文件中包含两次该头文件。
在这里插入图片描述
3)再通过命令行调用编译器,对源文件进行预处理。注意这里没有 -E 参数,因为结构体重复定义是在编译过程中报错。

tricore-gcc program.c -o program.i

在这里插入图片描述
如上图中,指明了struct1这个结构体类型重复定义了。

4.2 通过条件编译只加载一次头文件

有一种标准的方法解决上述问题,就是将源文件的整个内容包含在条件编译中,范例如下:

/* File foo. */
#ifndef FILE_FOO_SEEN
#define FILE_FOO_SEEN

the entire file

#endif /* !FILE_FOO_SEEN */

其中 #ifndef 表示如果后面的宏没有被定义,则执行下面到#endif之前的内容。当头文件第一次被包含的时候,还没有定义 FILE_FOO_SEEN 这个宏,就会先定义这个宏,扫描头文件的内容(也就是上述范例的 the entire file)然后展开到源文件中;当头文件第二次被包含的时候,由于第一次定义了这个宏,所以就直接跳到 #endif 了,也就不会再加载一次了。

对4.1中的源文件做预处理,就可以看到对比结果。

1)当没有用条件编译的时候,预处理后会把结构体类型的定义加载两次,也就导致了后面编译过程的报错。
在这里插入图片描述
2)在头文件中加上条件编译如下。
在这里插入图片描述
然后再进行一次预处理,输出的i文件如下图。这样就只有一个结构体定义了。
在这里插入图片描述

5 总结

本文研究了预处理过程中对头文件的处理,有助于理解头文件的作用。

>>返回个人博客总目录

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值