0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

编译器怎么处理同名头文件

嵌入式软件实战派 来源:嵌入式软件实战派 2024-11-05 16:51 次阅读

C语言中的include很简单,但不是你想象中的简单。

之前写过一个《C语言的include没你想的那么简单》,广受大家喜爱,详见《C语言的include没你想的那么简单(图文版)》或《C语言的Include没你想的那么简单(视频版)》。

最近又遇到个新问题,对于同名头文件,编译器是怎么处理的?

我这个踩坑过程就不细说了,说多了都是泪,直接上干货吧!

如果你嫌我啰嗦,你就直接拖到文末看截图的结果汇总吧!

为了讲清楚这个问题,我做了个实验,编了个这样的目录结构和文件:

./
│  main.c
│
├─inc1
│      inc.h
│      inc1.c
│
└─inc2
        inc.h
而这些文件内容分别如下: (1)./main.c
// ./main.c
#include 
#include "inc.h"


extern int inc1(void);


int main(void)
{
    printf("main VAL=%d
",VAL);
    printf("inc1 VAL=%d
",inc1());


    return 0;
}
(2)./inc1/inc.h
// ./inc1/inc.h
#ifndef _INC_H_
#define _INC_H_
  #pragma message(__FILE__)
  #define VAL 1
#endif
(3)./inc1/inc1.c
// ./inc1/inc1.c
#include "inc.h"
int inc1(void)
{
    return VAL;
}
(4)./inc2/inc.h
//./inc2/inc.h
#ifndef _INC_H_
#define _INC_H_
  #pragma message(__FILE__)
  #define VAL 2
#endif
然后,我分别用Cygwin上的GCC、Linux上的GCC、Window上的GreenHills和Windows上的ARMCC做了测试。 首先,直接在Windows上的命令窗口上直接执行(基于Cygwin上的GCC):
gcc .main.c.inc1inc1.c-omain
得到的是
.main.c:2:10: fatal error: inc.h: No such file or directory
    2 | #include "inc.h"
      |          ^~~~~~~
compilation terminated.
.inc1inc1.c:1:10: fatal error: inc.h: No such file or directory
    1 | #include "inc.h"
      |          ^~~~~~~
compilation terminated.

你会发现有两个错误,.main.c里面的inc.h找不到还好理解,但是.inc1inc1.c里面的inc.h也找不到?跟inc1.c同级的目录下有一个inc.h啊?!
接下来,通过编译选项-I(指定头文件路径)加入头文件路径看看。
 gcc .main.c .inc1inc1.c -Iinc1 -Iinc2 -o main
得到的是
In file included from .main.c:2:
inc1/inc.h:3:11: note: '#pragma message: inc1/inc.h'
    3 |   #pragma message(__FILE__)
      |           ^~~~~~~
In file included from .inc1inc1.c:1:
inc1/inc.h:3:11: note: '#pragma message: inc1/inc.h'
    3 |   #pragma message(__FILE__)
      |           ^~~~~~~

两个地方认的都是inc1/inc.h。可以理解,-Iinc1 -Iinc2哪个先就用哪个。
接着,只指定-Iinc2,看看什么效果
 gcc .main.c .inc1inc1.c -Iinc2 -o main
得到的是
Infileincludedfrom.main.c:2:
inc2/inc.h:3:11: note: '#pragma message: inc2/inc.h'
  3 |  #pragma message(__FILE__)
   |      ^~~~~~~
In file included from .inc1inc1.c:1:
inc2/inc.h:3:11: note: '#pragma message: inc2/inc.h'
  3 |  #pragma message(__FILE__)
|^~~~~~~

好家伙,两个地方都认的是inc2/inc.h!.inc1inc1.c为什么不要它旁边的inc1/inc.h呢?

难道通过-I指定路径的优先级是最高的?接下来,通过-I指定一个空路径试试。
gcc.main.c.inc1inc1.c-I-Iinc1-Iinc2-o main

得到的是

In file
included from .main.c:2:
inc2/inc.h:3:11:
note: '#pragma message: inc2/inc.h'
 3 |  #pragma message(__FILE__)
 |           ^~~~~~~
In file
included from .inc1inc1.c:1:
inc2/inc.h:3:11:
note: '#pragma message: inc2/inc.h'
 3 |  #pragma message(__FILE__)
 |           ^~~~~~~

看清楚这里哦-I-Iinc1-Iinc2,按刚才的推测,-I的优先级是最高的,但是这个-I是什么路径?导致最终用的头文件是inc2/inc.h??

不行,再来一发,将-I改为-I./,这样又会怎样呢?
gcc .main.c .inc1inc1.c -I./ -Iinc1 -Iinc2 -o main

得到的是

Infileincludedfrom.main.c:2:
inc1/inc.h:3:11: note: '#pragma message: inc1/inc.h'
    3 |   #pragma message(__FILE__)
      |           ^~~~~~~
In file included from .inc1inc1.c:1:
inc1/inc.h:3:11: note: '#pragma message: inc1/inc.h'
    3 |   #pragma message(__FILE__)
      |           ^~~~~~~
凌乱了吧,-I和-I./是不一样的?!

等等,是不是Windows这“/”和“”不一样,Powershell和Cygwin杂交就不一样了?? 于是,我找了个纯血的Linux+GCC试试。把路径中的换成/:

gcc ./main.c./inc1/inc1.c-omain

./main.c:2
fatal error: inc.h: No such file or directory
 2 | #include "inc.h"
 |         ^~~~~~~
compilation
terminated.
In file
included from ./inc1/inc1.c
./inc1/inc.h:3
note: '#pragma message: ./inc1/inc.h'
 3 |  #pragma message(__FILE__)
 |           ^~~~~~~

果真,对比上面第一个案例,这里只提示一个错误,说明如果不用-I指定头文件,编译器是可以就近找到当前路径的头文件的。
接下来,再看一个例子
gcc ./main.c./inc1/inc1.c-Iinc2-omain
In file
included from ./main.c:2:
inc2/inc.h:3:11:
note: '#pragma message: inc2/inc.h'
 3 |  #pragma message(__FILE__)
 |           ^~~~~~~
In file
included from ./inc1/inc1.c:1:
./inc1/inc.h:3:11:
note: '#pragma message: ./inc1/inc.h'
 3 |  #pragma message(__FILE__)
 |           ^~~~~~~

这里说明,并不是-Iinc2指定的优先级是最高的,./inc1/inc1.c还是能找到最近的头文件./inc1/inc.h。

这说明什么呢?不知道,不好说,反正我就不相信网上说的那些,我只相信实验出来的结果。

小平同志说过:实践是检验真理的唯一标准!

那么,我就用我电脑上的其他几个编译器(Greenhills里的CCRH850、S32DS里的ARMCC),全部搞一遍,做个对比。我用红框把异类标出来了: b45dae76-90b5-11ef-a511-92fbcf53809c.png

然后,有什么规律呢,自己总结哈!我是不记这些的,写几个代码试试就知道结果了。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7614

    浏览量

    137496
  • 编译器
    +关注

    关注

    1

    文章

    1642

    浏览量

    49246
  • 头文件
    +关注

    关注

    0

    文章

    25

    浏览量

    9896

原文标题:C语言的include没你想的那么简单(同名问题)

文章出处:【微信号:embedded_sw,微信公众号:嵌入式软件实战派】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    【Makefile】C文件包含的头文件修改,但不重新编译

    【Linux + Makefile】Makefile的高阶用法:解决C文件包含的头文件修改了,但C文件不重新编译的问题!
    的头像 发表于 09-08 08:53 5521次阅读
    【Makefile】C<b class='flag-5'>文件</b>包含的<b class='flag-5'>头文件</b>修改,但不重新<b class='flag-5'>编译</b>?

    求助,COSMIC编译器头文件IOSTM8.H的相关问题求解

    我的时钟CLK_ICKR在两个头文件中不一样,我没更改过头文件,这是什么情况呢?请大家说说 RM0016中的名字是:CLK_ICKR iostm8.h中的名字是:CLK_ICKR iostm8s.h中名字是:CLK_ICKCR(错误) 但
    发表于 04-28 06:21

    盛群ht-ide3000编译器怎么添加自己编的头文件

    使用盛群公司的ht-ide3000编译器时,由于在程序中使用了数学函数等等,需要包含等头文件,但是我在工程下面的在头文件中包含该文件后,编译器
    发表于 04-03 23:42

    XC8编译器头文件定义

    本人新手,想请教论坛中PIC编程高手几个问题,关于XC8编译器头文件定义的。仅有8分全奉献了。1、这个条件汇编是什么意思?具体_LIB_BUILD是什么意思?#ifndef
    发表于 01-22 14:25

    C 18编译器头文件问题

    当我试图在C 18编译器中包含头文件时。它在头文件末尾引发语法错误。
    发表于 04-10 09:19

    Bat 文件编译器

    Bat 文件编译器汇编语言源程序代码:; BAT2EXEC.COM - a batch file compiler;; BAT2EXEC filename;; Revision
    发表于 05-06 16:42 6次下载

    STC单片机在KEIL编译器中的头文件

    STC单片机在keil编译器里找不到头文件如何处理。首先在网络上找到一个关于STC单片机的升级包。安装上去以后,就可以看到有STC型号的单片机可以选择了。但是此时,它的头文件却无法
    发表于 08-26 10:52 8287次阅读

    C语言中程序员编写的头文件编译器自带的头文件

    #include 指令会指示 C 预处理器浏览指定的文件作为输入。预处理器的输出包含了已经生成的输出,被引用文件生成的输出以及 #include 指令之后的文本输出。例如,如果您
    的头像 发表于 11-12 14:55 7881次阅读

    ASM源文件编译器软件免费下载

    本文档的主要内容详细介绍的是ASM源文件编译器软件免费下载。适用于32位计算机,asm编译器,将ASM51.exe放在同一目录,在dos状态编译 如; d:asm51.exe ***.
    发表于 08-07 08:00 6次下载
    ASM源<b class='flag-5'>文件</b><b class='flag-5'>编译器</b>软件免费下载

    编程中引用头文件的几种方法及要点

    《》 #include使用引号“” 还是 尖括号《》 这个是有规定的。 通常来说:系统自带的头文件用尖括号括起来,这样编译器会在系统文件目录下查找。 #include 《xxx.h》 用户自定义的
    的头像 发表于 03-12 17:30 3402次阅读

    Verilog HDL 编译器指令说明

    编译时,特定的编译器指令在整个编译过程中有效(编译过程可跨越多个文件),直到遇到其它的不同编译
    的头像 发表于 11-03 09:31 3850次阅读
    Verilog HDL <b class='flag-5'>编译器</b>指令说明

    编译器将.c文件编译为.o文件链接的过程

    对大多数童鞋来说理解编译器将.c文件编译为.o文件并不大困难,但是却难以明白最后链接的过程是什么作用和为什么要这样做?
    的头像 发表于 10-13 09:36 5029次阅读

    C语言头文件路径的剖析

    编译器编译过程中会按照这些路径信息到指定的位置去查找头文件,然后通过预处理器作展开处理。在查找头文件
    的头像 发表于 02-17 09:44 1936次阅读
    C语言<b class='flag-5'>头文件</b>路径的剖析

    Triton编译器功能介绍 Triton编译器使用教程

    。以下是 Triton 编译器的一些功能介绍和使用教程。 Triton 编译器功能介绍 多语言支持 :Triton 支持多种编程语言,使得开发者可以在同一个编译器框架下处理不同的语言。
    的头像 发表于 12-24 17:23 578次阅读

    Triton编译器与其他编译器的比较

    Triton编译器与其他编译器的比较主要体现在以下几个方面: 一、定位与目标 Triton编译器 : 定位:专注于深度学习中最核心、最耗时的张量运算的优化。 目标:提供一个高度抽象、灵活、高效
    的头像 发表于 12-24 17:25 457次阅读