為什麼不常見include c檔案

2021-06-27 09:36:07 字數 3833 閱讀 1356

首先要指出的是:

對於#include  ,編譯器從標準庫路徑開始搜尋 filename.h

對於#include  「filename.h」 ,編譯器從使用者的工作路徑開始搜尋 filename.h

今天有人問我: #include能不能include乙個(多個.c檔案)?

為什麼經常見到include .h檔案而不是include .c檔案?或者說include是不是就是為包含.h檔案設定的語法?這個問題的答案偶不知道,沒有見有文件記載、說明這個問題。不過從語法角度講,include的意思就是從當前位置包含另外乙個檔案,就象巨集替換一樣把當前行用另外乙個檔案的整個內容替換掉。

從這點講,include .c檔案是可行的,c編譯器完全能夠正常處理。但是為什麼不常見include .c檔案?從設計角度上講,源**區分為.h和.c檔案,是為了介面與實現的分離,實際上兩者沒什麼本質的差別。.h檔案提供介面,.c檔案提供具體的實現,兩者可以一一對應,也可以不一一對應,沒有強制要求。乙個.c檔案做為乙個模組的實現,有可能要跟其他的模組打交道,這個時候就需要include其他模組的介面(其他模組的.h檔案);而包含其他模組的實現(.c檔案)是沒有意義的、危險的。

所以,我們不應該在專案中include .c檔案,這樣使用者出於直覺很難想到這裡會有問題,增加了排錯的難度。前幾天偶移植乙個國際知名大公司的**就遇到了這個問題,耗費了半天的時間檢視了全部的原始碼和makefile才發現了這個不常見編譯現象。當然,那個公司的**之所以這麼做,是他認為這些**已經很成熟了,不需要修改和反覆重新編譯。但它的做法確實對我的除錯造成了很大的障礙。

----- gnu make document 中的相關章節 -----

4.12 自動生成依賴

在為乙個程式編寫的makefile檔案中,常常需要寫許多僅僅是說明一些obj檔案依靠標頭檔案的規則。例如,如果『main.c』通過一條#include語句使用『defs.h』,您需要寫入下的規則:

main.o: defs.h

您需要這條規則讓make知道如果『defs.h』一旦改變必須重新構造『main.o』。由此您可以明白對於乙個較大的程式您需要在makefile檔案中寫很多這樣的規則。而且一旦新增或去掉一條#include語句您必須十分小心地更改makefile檔案。

為避免這種煩惱,現代c編譯器根據原程式中的#include語句可以為您編寫這些規則。如果需要使用這種功能,通常可在編譯源程式時加入『-m』開關,例如,下面的命令:

cc -m main.c

產生如下輸出:

main.o : main.c defs.h

這樣您就不必再親自寫這些規則,編譯器可以為您完成這些工作。

注意,由於在makefile檔案中提及構造『main.o』,因此『main.o』將永遠不會被隱含規則認為是中間檔案而進行搜尋,這同時意味著make不會在使用它之後自動刪除它;參閱隱含規則鏈。

對於舊版的make程式,通過乙個請求命令,如『make depend』,利用編譯器的特點生成依賴是傳統的習慣。這些命令將產生乙個『depend』檔案,該檔案包含所有自動生成的依賴;然後makefile 檔案可以使用include命令將它們讀入(參閱包含其它makefile檔案)。

在gnu make中,重新構造makefile檔案的特點使這個慣例成為了過時的東西――您永遠不必具體告訴make重新生成依賴,因為gnu make總是重新構造任何過時的makefile檔案。參閱makefile檔案的重新生成的過程。

我們推薦使用自動生成依賴的習慣是把makefile檔案和源程式檔案一一對應起來。如,對每乙個源程式檔案『name.c』有一名為『name.d』的 makefile檔案和它對應,該makefile檔案中列出了名為『name.o』的obj檔案所依賴的檔案。這種方式的優點是僅在源程式檔案改變的情況下才有必要重新掃瞄生成新的依賴。

這裡有乙個根據c語言源程式『name.c』生成名為『name.d』依賴檔案的格式規則:

%.d: %.c

set -e; $(cc) -m $(cppflags) $< \

| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \

[ -s $@ ] || rm -f $@

關於定義格式規則的資訊參閱定義與重新定義格式規則。『-e』開關是告訴shell如果$(cc)命令執行失敗(非零狀態退出)立即退出。正常情況下,shell退出時帶有最後乙個命令在管道中的狀態(sed),因此make不能注意到編譯器產生的非零狀態。

對於gnu c編譯器您可以使用『-mm』開關代替『-m』,這是省略了有關系統標頭檔案的依賴。詳細內容參閱《gnu cc使用手冊》中控制預處理選項。

命令sed的作用是翻譯(例如):

main.o : main.c defs.h

到:main.o main.d : main.c defs.h

這使每乙個『.d』檔案和與之對應的『.o』檔案依靠相同的源程式檔案和標頭檔案,據此,make可以知道如果任乙個源程式檔案和標頭檔案發生變化,則必須重新構造依賴檔案。

一旦您定義了重新構造『.d』檔案的規則,您可以使用使用include命令直接將它們讀入,(參閱包含其它makefile檔案),例如:

sources = foo.c bar.c

include $(sources:.c=.d)

(這個例子中使用乙個代替變數參照從源程式檔案列表『foo.c bar.c'翻譯到依賴檔案列表『foo.d bar.d'。詳細內容參閱替換引用。)所以,『.d』的makefile檔案和其它makefile檔案一樣,即使沒用您的任何進一步的指令,make 同樣會在必要的時候重新構建它們。參閱makefile檔案的重新生成過程。

gnu make手冊的開頭就說出了很多人不知道的知識——它不僅僅用於編譯的:p 

----- gnu make document 中的相關章節 ----- 

gnu make符合ieee standard 1003.2-1992 (posix.2) 6.2章節的規定。 

因為c語言程式更具有代表性,所以我們的例子基於c語言程式,但make並不是僅僅能夠處理c語言程式,它可以處理那些編譯器能夠在shell命令下執行的的各種語言的程式。事實上,gnu make不僅僅限於程式,它可以適用於任何如果一些檔案變化導致另外一些檔案必須更新的任務。 

如果要使用make,必須先寫乙個稱為makefile的檔案,該檔案描述程式中各個檔案之間的相互關係,並且提供每乙個檔案的更新命令。在乙個程式中,可執行程式檔案的更新依靠obj檔案,而obj檔案是由原始檔編譯得來的。 

一旦合適的makefile檔案存在,每次更改一些原始檔,在shell命令下簡單的鍵入: 

make 

就能執行所有的必要的重新編譯任務。make程式根據makefile檔案中的資料和每個檔案更改的時間戳決定哪些檔案需要更新。對於這些需要更新的檔案,make基於makefile檔案發布命令進行更新,進行更新的方式由提供的命令列引數控制。

這屬於濫用#include. 

為何要分為標頭檔案和原始檔?本來就是為了傳遞如下資訊: 

型別定義 

外部函式原型 

外部變數 

巨集 這部分不產生任何實際**的東西。 

c各檔案之間的**是通過#include來引入的嗎?這屬於聯結器的工作! 

懷疑使用這個的人,也許是因為原始檔的**太長了,就濫用#include,將源**分到幾個檔案上。 

我估計將實現這種招數的辦法是將源**劃分為乙個主多個從的關係,主的引入所有從檔案。 

他們的內容有如下規定: 

主檔案,包括所有外部連線的**(公共) 

從檔案,所有元素具備內部連線(私有) 

對於客戶端來說,只有主檔案才是他們真正去要連線的。 

而因為從檔案都是內部連線,相關的.obj將毫無疑義的被丟棄,因為主檔案有著一模一樣的拷貝。 

當然更蹩腳的辦法是將這些#include了的原始檔排除出專案定義檔案。

0 給主人留下些什麼吧!~~

甲骨文為什麼Linux?

大家知道,linux 是一種作業系統核心,是個名詞。在本文標題中,linux 被當成了謂語,意思是說,甲骨文開始從事 linux 業務。甲骨文 即 oracle 公司 是著名的資料庫 中介軟體和應用軟體產品全球 商,有數千名員工分布在世界各地,公司年收入高達 170億美元。10月 25日,甲骨文宣布...

我為什麼要寫博文?要寫什麼樣的博文?

自我介紹 首先自我介紹一下,我是靜心盡力,自學計算機多年,乙個命途多舛歷盡千帆仍是不忘初心的 少年 現就讀於普通的四非學校 非985,211,一流大學,一流學科 至於為什麼這樣形容自己,我會在另一篇博文中介紹,至於靜心盡力當然是網名,之所以取這個名字呢,因為感到現在的人們 包括我自己 內心都有些浮躁...

為什麼你的「努力」一文不值?

讓乙個研究生男收集乙份資料,快下班了問結果,竟然毛也沒有。見我要怒,他慷慨激昂地說 我已經很努力找了,但真的查不到。作為主管,我已經努力 這話我不知聽過多少次,每次都要面對一張無比誠懇的臉。但我要說 你的 努力 一文不值!一 工作以後還把 努力 當免死金牌的人,都是混入職場的 學生黨 當年他們考試沒...