首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

预处理过程:头文件

  • 23-09-22 01:23
  • 3042
  • 5208
blog.csdn.net

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

文章目录

  • 1 Include语法
  • 2 编译器对Include的处理
  • 3 头文件的搜索路径
  • 4 只加载一次头文件
    • 4.1 问题
    • 4.2 通过条件编译只加载一次头文件
  • 5 总结

1 Include语法

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

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

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

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
  • 1

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

3 头文件的搜索路径

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

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

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

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

4 只加载一次头文件

4.1 问题

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

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

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

tricore-gcc program.c -o program.i
  • 1

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

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

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

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

the entire file

#endif /* !FILE_FOO_SEEN */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

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

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

5 总结

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

>>返回个人博客总目录

注:本文转载自blog.csdn.net的chhttty的文章"https://blog.csdn.net/u013288925/article/details/114292754"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top