0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

編譯器怎么處理同名頭文件

嵌入式軟件實戰(zhàn)派 ? 來源:嵌入式軟件實戰(zhàn)派 ? 2024-11-05 16:51 ? 次閱讀

C語言中的include很簡單,但不是你想象中的簡單。

之前寫過一個《C語言的include沒你想的那么簡單》,廣受大家喜愛,詳見《C語言的include沒你想的那么簡單(圖文版)》或《C語言的Include沒你想的那么簡單(視頻版)》。

最近又遇到個新問題,對于同名頭文件,編譯器是怎么處理的?

我這個踩坑過程就不細說了,說多了都是淚,直接上干貨吧!

如果你嫌我啰嗦,你就直接拖到文末看截圖的結(jié)果匯總吧!

為了講清楚這個問題,我做了個實驗,編了個這樣的目錄結(jié)構(gòu)和文件:

./
│  main.c
│
├─inc1
│      inc.h
│      inc1.c
│
└─inc2
        inc.h
而這些文件內(nèi)容分別如下: (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上的命令窗口上直接執(zhí)行(基于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.

你會發(fā)現(xiàn)有兩個錯誤,.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指定路徑的優(yōu)先級是最高的?接下來,通過-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的優(yōu)先級是最高的,但是這個-I是什么路徑?導(dǎo)致最終用的頭文件是inc2/inc.h??

不行,再來一發(fā),將-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指定的優(yōu)先級是最高的,./inc1/inc1.c還是能找到最近的頭文件./inc1/inc.h。

這說明什么呢?不知道,不好說,反正我就不相信網(wǎng)上說的那些,我只相信實驗出來的結(jié)果。

小平同志說過:實踐是檢驗真理的唯一標準!

那么,我就用我電腦上的其他幾個編譯器(Greenhills里的CCRH850、S32DS里的ARMCC),全部搞一遍,做個對比。我用紅框把異類標出來了: b45dae76-90b5-11ef-a511-92fbcf53809c.png

然后,有什么規(guī)律呢,自己總結(jié)哈!我是不記這些的,寫幾個代碼試試就知道結(jié)果了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7595

    瀏覽量

    135923
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1617

    瀏覽量

    49019
  • 頭文件
    +關(guān)注

    關(guān)注

    0

    文章

    25

    瀏覽量

    9843

原文標題:C語言的include沒你想的那么簡單(同名問題)

文章出處:【微信號:embedded_sw,微信公眾號:嵌入式軟件實戰(zhàn)派】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    【Makefile】C文件包含的頭文件修改,但不重新編譯?

    【Linux + Makefile】Makefile的高階用法:解決C文件包含的頭文件修改了,但C文件不重新編譯的問題!
    的頭像 發(fā)表于 09-08 08:53 ?5209次閱讀
    【Makefile】C<b class='flag-5'>文件</b>包含的<b class='flag-5'>頭文件</b>修改,但不重新<b class='flag-5'>編譯</b>?

    求助,COSMIC編譯器頭文件IOSTM8.H的相關(guān)問題求解

    我的時鐘CLK_ICKR在兩個頭文件中不一樣,我沒更改過頭文件,這是什么情況呢?請大家說說 RM0016中的名字是:CLK_ICKR iostm8.h中的名字是:CLK_ICKR iostm8s.h中名字是:CLK_ICKCR(錯誤) 但
    發(fā)表于 04-28 06:21

    盛群ht-ide3000編譯器怎么添加自己編的頭文件

    使用盛群公司的ht-ide3000編譯器時,由于在程序中使用了數(shù)學函數(shù)等等,需要包含等頭文件,但是我在工程下面的在頭文件中包含該文件后,編譯器
    發(fā)表于 04-03 23:42

    XC8編譯器頭文件定義

    本人新手,想請教論壇中PIC編程高手幾個問題,關(guān)于XC8編譯器頭文件定義的。僅有8分全奉獻了。1、這個條件匯編是什么意思?具體_LIB_BUILD是什么意思?#ifndef
    發(fā)表于 01-22 14:25

    #include <ioavr.h>這個頭文件我應(yīng)該下什么編譯器

    第一次接觸AVR,手上有一個別人個文件。芯片型號:ATMEGA16A,我下載了一個ICCV7,把別人的.c和.h全部加到工程里面編譯,但是發(fā)現(xiàn)下面這些頭文件找不到,網(wǎng)上看了一下好像說編譯器
    發(fā)表于 03-26 18:01

    C 18編譯器頭文件問題

    當我試圖在C 18編譯器中包含頭文件時。它在頭文件末尾引發(fā)語法錯誤。
    發(fā)表于 04-10 09:19

    Bat 文件編譯器

    Bat 文件編譯器匯編語言源程序代碼:; BAT2EXEC.COM - a batch file compiler;; BAT2EXEC filename;; Revision
    發(fā)表于 05-06 16:42 ?6次下載

    STC單片機在KEIL編譯器中的頭文件

    STC單片機在keil編譯器里找不到頭文件如何處理。首先在網(wǎng)絡(luò)上找到一個關(guān)于STC單片機的升級包。安裝上去以后,就可以看到有STC型號的單片機可以選擇了。但是此時,它的頭文件卻無法
    發(fā)表于 08-26 10:52 ?8221次閱讀

    C語言中程序員編寫的頭文件編譯器自帶的頭文件

    #include 指令會指示 C 預(yù)處理器瀏覽指定的文件作為輸入。預(yù)處理器的輸出包含了已經(jīng)生成的輸出,被引用文件生成的輸出以及 #include 指令之后的文本輸出。例如,如果您
    的頭像 發(fā)表于 11-12 14:55 ?7789次閱讀

    ASM源文件編譯器軟件免費下載

    本文檔的主要內(nèi)容詳細介紹的是ASM源文件編譯器軟件免費下載。適用于32位計算機,asm編譯器,將ASM51.exe放在同一目錄,在dos狀態(tài)編譯 如; d:asm51.exe ***.
    發(fā)表于 08-07 08:00 ?5次下載
    ASM源<b class='flag-5'>文件</b><b class='flag-5'>編譯器</b>軟件免費下載

    華為方舟編譯器使用指南

    的優(yōu)化,最終生成二進制文件,二進制文件編譯器運行時庫文件鏈接生成可執(zhí)行文件,在方舟的運行環(huán)境
    發(fā)表于 10-14 14:56 ?1次下載
    華為方舟<b class='flag-5'>編譯器</b>使用指南

    編程中引用頭文件的幾種方法及要點

    《》 #include使用引號“” 還是 尖括號《》 這個是有規(guī)定的。 通常來說:系統(tǒng)自帶的頭文件用尖括號括起來,這樣編譯器會在系統(tǒng)文件目錄下查找。 #include 《xxx.h》 用戶自定義的
    的頭像 發(fā)表于 03-12 17:30 ?3283次閱讀

    Verilog HDL 編譯器指令說明

    編譯時,特定的編譯器指令在整個編譯過程中有效(編譯過程可跨越多個文件),直到遇到其它的不同編譯
    的頭像 發(fā)表于 11-03 09:31 ?3589次閱讀
    Verilog HDL <b class='flag-5'>編譯器</b>指令說明

    編譯器將.c文件編譯為.o文件鏈接的過程

    對大多數(shù)童鞋來說理解編譯器將.c文件編譯為.o文件并不大困難,但是卻難以明白最后鏈接的過程是什么作用和為什么要這樣做?
    的頭像 發(fā)表于 10-13 09:36 ?4723次閱讀

    C語言頭文件路徑的剖析

    編譯器編譯過程中會按照這些路徑信息到指定的位置去查找頭文件,然后通過預(yù)處理器作展開處理。在查找頭文件
    的頭像 發(fā)表于 02-17 09:44 ?1813次閱讀
    C語言<b class='flag-5'>頭文件</b>路徑的剖析