【環境】
> KEIL5.25
> win10
> @2018-4-23
【問題】
頭文件互包含導致的錯誤(使用了另一文件的類型定義)
文件<fileA.h>
1 <fileA.h> 2 3 #ifndef __FILEA_H__ 4 #define __FILEA_H__ 5 6 #include "fileB.h" 7 8 typedef struct 9 { 10 int var; 11 }stuct_A_s; 12 13 14 #endif
文件<fileB.h>
1 <fileB.h> 2 3 #ifndef __FILEB_H__ 4 #define __FILEB_H__ 5 6 #include "fileA.h" 7 8 typedef struct 9 { 10 int var; 11 struct_A_s obj; 12 }struct_B_s; 13 14 #endif
編譯后報錯:在文件<fileB.h>中 error: #20: identifier "struct_A_s" is undefined
【分析】
導致上述錯誤的原因,是在文件<fileA.h>中,使用了 fileB.h,而文件<fileB.h>中使用的類 struct_A_s 在其定義之前,故產生了先使用后定義的語法錯誤
具體分析:
從文件<fileA.h>開始分析:
> 執行避免頭文件重復包含的宏 --- <fileA.h>
> 包含文件<fileB.h>,進入文件<fileB.h>
> 執行避免頭文件重復包含的宏 --- <fileB.h>
> 包含文件<fileA.h>,進入文件<fileA.h>
> 由於避免重復包含宏的控制,進不去A文件內容部分,跳轉回文件<fileB.h>
> 執行結構體 struct_B_s 定義,結構體成員類型使用了結構體 struct_A_s ,這就出現了使用了未定義的情況,執行完畢跳轉回文件<fileA.h>
> 執行結構體 struct_A_s 定義,結合上一步就發生了先使用后定義的問題,執行完畢結束
結論:編譯器先從文件<fileA.h>開始編譯就會出現本文所示錯誤
從文件<fileB.h>開始分析:
> 執行避免頭文件重復包含的宏 --- <fileB.h>
> 包含文件<fileA.h>,進入文件<fileA.h>
> 執行避免頭文件重復包含的宏 --- <fileA.h>
> 包含文件<fileB.h>,進入文件<fileB.h>
> 由於避免重復包含宏的控制,進不去B文件內容部分,跳轉回文件<fileA.h>
> 執行結構體 struct_A_s 定義,執行完畢跳轉回文件<fileB.h>
> 執行結構體 struct_B_s 定義,執行完畢結束
結論:編譯器先從文件<fileB.h>開始編譯就不會報錯誤
【解決】
# 去除文件<fileA.h>中包含文件<fileB.h>的語句部分,可解決此問題
# 由於分析推出是編譯順序導致錯誤的出現,特做了一下一些事做實驗:
> 控制文件 <fileA.h> 與 <fileB.h> 的編譯順序 (做了文件名的更改,即按照字母表順序修改文件名達到兩次編譯時兩個文件的排序相異)
> 兩次編譯的結果都是報相同的錯誤,error: #20: identifier "struct_A_s" is undefined
【結論】
# 綜上暫推出,編譯器在編譯時,每個文件都會單獨編譯一遍,所以不論文件 <fileA.h> 與 <fileB.h> 的排序,都會出現相同的問題
# 一般是杜絕文件互相包含的,因為文件包含的意義就是要使用被包含文件的一些定義,互相包含就會出現先使用后定義 的情況發生
# 了解一些編譯原理的知識后,將會得到更權威的解惑,以上只是根據現象分析的結果