為什麼c 要「在標頭檔案中宣告,在原始檔中定義」?

時間 2021-05-29 22:57:51

1樓:Coder

為什麼不推薦在標頭檔案中定義函式或者變數呢,只建議在標頭檔案中宣告變數和函式...

要記住,每當你用乙個#include的時候,你就是把那個標頭檔案的內容搬到#include的位置

#pragma once的作用是:在同乙個檔案中多次include同乙個標頭檔案的時候, 保證該標頭檔案內容只被替換一次, 並會為以下情況提供保證:多個不同檔案include同乙個標頭檔案, 然後這個標頭檔案內容只在其中的乙個檔案中被替換。

所以呢,如果你在兩個.c檔案(比如a.c, b.

c)都#include ''header.h'',並且header.h中定義乙個函式func(注意不是宣告), 那經過預處理階段後, a.

c和b.c中都會有func的函式體(定義體),那鏈結階段肯定會出錯———重複定義乙個函式,,,

解決也有很多辦法,比如在標頭檔案中把函式func宣告為static,或者inline, 但最根本的辦法還是,,只在標頭檔案中宣告變數和函式,而不是定義它們...

變數,函式可以多次宣告,,,,不可以多次定義

2樓:小小大轟龍

只有在 header 裡宣告,在 cpp 裡定義才能在編譯的時候得到每個類和函式的完全相同的定義。

如果沒有 header,所有的宣告和定義都在 cpp 裡面,編譯的時候也必須 include 這個 cpp 檔案,會增加編譯的時間。

方便同事查介面和函式原型。

c++20 引入了 module 應該會方便很多。

3樓:風吹歪

#include命令是把檔案所有內容整個替換到命令的位置,所以如果你的標頭檔案包含了實現,並且在多個檔案種include這個標頭檔案,就會產生重定義錯誤

但是只要你明白自己在做什麼,在標頭檔案裡定義也不是不可以,有很多single header library就是這樣做的,這樣的好處就是你可以像指令碼語言那樣import模組了,突出乙個方便

4樓:徐博的大哥

在我看來,cpp並不需要嚴格地遵從在標頭檔案中宣告,原始檔中定義這一最標準的準則!完全可以在標頭檔案中進行申明和定義(不僅僅是模版類,內聯函式,另外資料結構,類中類等等它們的宣告和定義都可以在標頭檔案中進行;另外,也可以完全在原始檔中進行申明定義,然後別的模組去include這個原始檔!唯一需要保證的是,在乙個工程的link階段,函式或者變數只有一次定義!

另外寫cpp的時候,標頭檔案也不必要用.h來作為字尾,原始檔也不必非要用cpp為字尾!cpp和h檔案的分離最大的目的,在我看來是為了便於組織管理,以及方便二次開發時的呼叫!

5樓:

首先,我來回答末尾的「 .cpp檔案和.h檔案相互之間的關係」。

講到.h就必然會提到#include。#include是什麼?

一條預處理指令。於是你就需要搞清楚預處理在c++程式的編譯過程中大約發生在什麼環節。以下引用 cppreference.

com:

The preprocessor is executed at translation phase 4, before the compilation. The result of preprocessing is a single file which is then passed to the actual compiler.

c++的預處理器在編譯之前執行,它看到#include指令,就會把那個檔案的內容替換到當前位置。其它的預處理指令例如#define, #ifdef, ##等也在這個階段被執行、並產生相應的內容。

預處理器執行完成後,所有的預處理指令都會被移除。其結果是乙個單個頭的大檔案(我猜測這檔案只存在於記憶體裡),這個檔案才會被進一步傳給編譯器做編譯。

搞清楚這一點很重要。例如為什麼有人說,標頭檔案多了拖慢編譯速度。因為乙個.

h被多個cpp include,每個cpp編譯的時候都要重新編譯一遍這個.h啊。所以VS允許預編譯標頭檔案,也有些別的編譯器支援類似功能。

其次,為什麼要把函式、全域性變數的宣告放到標頭檔案裡,把定義放在cpp裡呢?

因為c++發明那會兒考慮到與c的相容性,c的一些規則也被帶了過來,比如先宣告後使用。因此,如果你定義了乙個函式:

return_type

function

(parameter_type

param1

,...)

你要在別的cpp裡使用,你必須先宣告一下:

return_type

function

(parameter_type

param1

,...);

這主要是告訴編譯器:我知道這麼個函式,它簽名長這樣,它的定義在別的地方。現在我可以用它了吧?

然後問題來了:假如你這個函式到處都要用到,你總不能每個cpp裡貼上這麼一行吧。

答案自然就是把它放在標頭檔案裡咯。這就是你書裡那句話的意思。

至於cpp自己發明的那套,class什麼的,又不完全遵守c的那一套了。比如class裡的function A呼叫B,並不要求B必須寫在A前面。以上。

6樓:好知

首先了解一下C++的編譯原理,有很多規則需要遵循,比如說兩個class相互依賴,需要怎麼做才能讓編譯器通過,於是乎出現了"class A;"這種語法。同樣標頭檔案中宣告也是一樣的道理,說白了就是要遵循規則。有很多人可能說,不一定,我經常在標頭檔案裡面寫類函式的定義或者inline函式也沒問題啊。

從語法角度來說,不可否認只要編譯過怎麼做都可以。同樣,我們可以對比兩種做法的優缺點:

(1)原始碼修改

定義在標頭檔案, 所有包含該標頭檔案的cpp都需要重新編譯定義在原始檔,只有被修改的原始檔被編譯

所有在vc的stdafx檔案或者一些注釋當中會說明, 盡可能避免標頭檔案改動。

(2)原始碼閱讀

定義在標頭檔案,穿插函式的定義的函式宣告列表定義在原始檔,清晰的函式宣告列表

對比一下就知道那種更容易閱讀了。

暫且到此結束,有空繼續噴!

7樓:暗黑謝廣坤

那我反過來說吧,不在標頭檔案中宣告或不在原始檔中定義。

1、不在標頭檔案中宣告,使用函式需要自己宣告,否則編譯錯誤找不到宣告。

2、不在標頭檔案中宣告且在原始檔中宣告,同1。

3、不在原始檔中定義,鏈結錯誤提示找不到符號。

4、不在原始檔中定義且在標頭檔案定義,非static的情況下,多處include出現鏈結錯誤提示重複定義符號。static的情況下,多次重複定義導致最終執行檔案變大。

根源在於include等同於檔案內容歸併,鏈結查詢符號。

8樓:Xi Yang

因為C沒有模組的概念,編譯結果裡面沒有程式設計介面。如果你想讓你的內容模組化,就只能把程式設計介面寫在乙個檔案裡,並稱之為標頭檔案。

9樓:SuperFashi

怎麼寫都可以,你可以寫個hpp,把宣告都寫在裡面,cpp裡再寫實現,也完全可以不要hpp,全都寫在cpp裡面。

前者的好處是方便檢視宣告,你可以把注釋都寫在hpp裡面,告訴使用者怎麼呼叫函式。後者的好處是……寫的東西少一點。

我個人還是喜歡後者。

10樓:耶倫奶奶

要從幾個部分解釋一下。

第一,預編譯指令#include的作用是將所包含的檔案全文複製到#include的位置,相當於是個展開為乙個檔案的巨集。

第二,C++允許多次宣告,但只允許一次實現。比如int foo();就是一次宣告,而int foo(){}就是一次實現。

如果編譯時有多個.cpp檔案中#include了同乙個含有函式實現的.h,這時候鏈結器就會在多個目標檔案中找到這個函式的實現,而這在C++中是不允許的,此時就會引爆LNK1169錯誤:

找到乙個或多個重定義的符號。

因此為了讓函式可以在各個.cpp中共享,正確的做法就是在.h中只宣告函式,並在另【 乙個(重點)】.cpp中實現這個函式。這樣就不會衝突了。

11樓:林飛

*h可以視作戶口登記表有人名(函式名)長相(返回值,參數列),類宣告可以視作乙個團隊,變數宣告可以視作物品列表

cpp視作登記表對應的人,團隊,物品

h裡面寫了乙個可以辦事的人,團隊,物品在哪叫啥長什麼樣,可以分發給不同的人這些人根據登記表裡面的記錄,知道了自己是什麼樣的(能幹什麼,需要什麼才能幹,也就是函式宣告),以及幹這個的能力(函式實現)。根據自己需要找到對應的人,團隊,物品。

你不能在乙個程式裡擁有多個完全一樣的人,團隊,物品。但是登記表可以有很多份

編譯器會將cpp檔案編譯成二進位制檔案,而cpp的include會將h裡的內容直接接在cpp內容的前面,h一般會存在於多個cpp中,所以h通常是個登記表而不是實際的人

手機打明天再用電腦更

為什麼C 中,含有函式宣告的標頭檔案應該被包含在定義函式的原始檔中?

如果,你在second.cpp裡面的function 1 裡呼叫了function 2 就會編譯不通過。並且,會提示你找不到function 2的定義。要不你試一下呢? 大JoeJoe 在實際的專案程式設計中 cpp檔案中定義的函式分為兩種,一種是對外提供介面供外部呼叫的,一種是特定功能封裝成乙個函...

c 能否把所有要用的標頭檔案在某乙個標頭檔案中全inlcude了,然後其他檔案只用include這個

qugx0528 每個cpp都是乙個編譯單元,編譯時生成多個obj檔案,在link的時候,也會極大的拖慢速度。有這麼一種情況,我有乙個很大的UI介面,其對應的實現 操作類也很龐大,我想把他們分解到多個cpp實現中。這樣就產生了這麼乙個問題 代表ui的標頭檔案會在每個cpp中被include一次,這樣...

為什麼在C 中泛型型別不能是Explicit Layout的?

這個LayoutKind列舉的 Explicit 的值,文件是這樣定義的 在未管理記憶體中的每乙個物件成員的精確位置是被顯式控制的,服從於Pack欄位的設定。每個成員必須使用FieldOffsetAttribute指示該字段在型別中的位置。就是,成員必須有FieldOffsetAttribute去顯...