C語言中的include很簡單,但不是你想象中的簡單。
之前寫過一個《C語言的include沒你想的那么簡單》,廣受大家喜愛,詳見《C語言的include沒你想的那么簡單(圖文版)》或《C語言的Include沒你想的那么簡單(視頻版)》。
最近又遇到個新問題,對于同名頭文件,編譯器是怎么處理的?
我這個踩坑過程就不細說了,說多了都是淚,直接上干貨吧!
如果你嫌我啰嗦,你就直接拖到文末看截圖的結果匯總吧!
為了講清楚這個問題,我做了個實驗,編了個這樣的目錄結構和文件:
./
│ main.c
│
├─inc1
│ inc.h
│ inc1.c
│
└─inc2
inc.h
而這些文件內容分別如下: (1)./main.c
// ./main.c #include(2)./inc1/inc.h#include "inc.h" extern int inc1(void); int main(void) { printf("main VAL=%d ",VAL); printf("inc1 VAL=%d ",inc1()); return 0; }
// ./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),全部搞一遍,做個對比。我用紅框把異類標出來了:

然后,有什么規律呢,自己總結哈!我是不記這些的,寫幾個代碼試試就知道結果了。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
C語言
+關注
關注
183文章
7644瀏覽量
145575 -
編譯器
+關注
關注
1文章
1672瀏覽量
51598 -
頭文件
+關注
關注
0文章
26瀏覽量
10322
原文標題:C語言的include沒你想的那么簡單(同名問題)
文章出處:【微信號:embedded_sw,微信公眾號:嵌入式軟件實戰派】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
熱點推薦
求助,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
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
?8721次閱讀
C語言中程序員編寫的頭文件和編譯器自帶的頭文件
#include 指令會指示 C 預處理器瀏覽指定的文件作為輸入。預處理器的輸出包含了已經生成的輸出,被引用文件生成的輸出以及 #include 指令之后的文本輸出。例如,如果您
ASM源文件編譯器軟件免費下載
本文檔的主要內容詳細介紹的是ASM源文件編譯器軟件免費下載。適用于32位計算機,asm編譯器,將ASM51.exe放在同一目錄,在dos狀態編譯 如; d:asm51.exe ***.
發表于 08-07 08:00
?6次下載
編程中引用頭文件的幾種方法及要點
《》 #include使用引號“” 還是 尖括號《》 這個是有規定的。 通常來說:系統自帶的頭文件用尖括號括起來,這樣編譯器會在系統文件目錄下查找。 #include 《xxx.h》 用戶自定義的
編譯器將.c文件編譯為.o文件鏈接的過程
對大多數童鞋來說理解編譯器將.c文件編譯為.o文件并不大困難,但是卻難以明白最后鏈接的過程是什么作用和為什么要這樣做?
Triton編譯器功能介紹 Triton編譯器使用教程
。以下是 Triton 編譯器的一些功能介紹和使用教程。 Triton 編譯器功能介紹 多語言支持 :Triton 支持多種編程語言,使得開發者可以在同一個編譯器框架下處理不同的語言。
Triton編譯器與其他編譯器的比較
Triton編譯器與其他編譯器的比較主要體現在以下幾個方面: 一、定位與目標 Triton編譯器 : 定位:專注于深度學習中最核心、最耗時的張量運算的優化。 目標:提供一個高度抽象、靈活、高效
編譯器怎么處理同名頭文件
評論