回覆列表
  • 1 # IT劉小虎

    一般來說,C語言專案中的檔案以其後綴名來看,常用的只有兩種:*.c檔案和 *. h 檔案,後者常被稱作“標頭檔案”,因為這種型別的檔案常常和 #include 關鍵字一起放在 *.c檔案的頭部, * . h 中的“h”常被認為是“header(頭)”的縮寫。

    大型C語言專案一般都是採用多檔案程式設計的開發方式,fun.c模組裡定義了 add() 函式,想在別的模組裡使用 add() 函式,只需要從 fun.c 檔案 extern add() 函式即可。

    關於 extern 關鍵字的介紹,可參考我的上一個回答。

    但是使用 fun.c 模組的每個檔案都需要重新宣告 add() 函式也是很麻煩的。而且,在C語言程式開發中,重複的程式碼應該儘量避免

    在C語言程式開發中使用標頭檔案

    為了不重複宣告 fun.c 模組裡定義的函式,有什麼辦法呢?答案就是使用標頭檔案。新建 fun.h 檔案,把

    fun.c

    模組中能夠提供給外界使用的函式或變數宣告在標頭檔案裡,以後要使用這些函式或者變數,只需要包含標頭檔案就可以了。請看相關C語言程式碼:

    如果想在main.c檔案中使用fun.c檔案中定義的函式,只需要包含fun.h就可以了,下面是一段C語言程式碼例子,請看:

    事實上,以後任何模組想呼叫fun.c中的函式,都只需包含fun.h即可。關於fun.h中內容,有幾點細節需要說明

    先說說為什麼 #include <stdio.h>用角括號,而#include “fun.h”用引號。對於用尖括號包含的標頭檔案,C語言編譯器會從系統的標頭檔案目錄查詢,例如我的 codeblocks 的系統標頭檔案路徑:

    對於引號包含的標頭檔案,C語言編譯器會首先查詢包含標頭檔案的 .c 檔案所在目錄,沒有找到再查詢系統的標頭檔案目錄。

    因為我們建立的 fun.h 檔案和 main.c 在同一目錄,所以在 main.c 檔案中包含 fun.h 標頭檔案要用引號,如果用尖括號包含編譯器就找不到 fun.h 檔案了,編譯就會報錯。

    避免標頭檔案的重複包含

    下面這幾條C語言程式碼屬於條件編譯語句,意思是如果沒有 define __FUN_H__ 就 define __FUN_H__ ,如果之前 define 過,#ifndef 到 #endif 的C語言程式碼段就不參與編譯了,這樣可以避免 #ifndef 到 #endif 的程式碼段被重複包含。

    __FUN_H__ 當然也可以改成其他名字,只需要確保唯一性就可以了。

    那為什麼需要防止重複包含呢?誰會把一個頭檔案包含兩次呢?像上面那麼明顯的錯誤沒人會犯,但有時候重複包含的錯誤並不是那麼明顯的。

    在規模較大的C語言專案中標頭檔案包含標頭檔案的情況很常見,經常會包含四五層,這時候重複包含的問題就很難發現了。

    比如在我的系統標頭檔案錄/usr/include中,errno.h包含了bits/errno.h,後者又包含了linux/errno.h,後者又包含了asm/errno.h,後者又包含了asm-generic/errno.h。

    另外一個問題是,就算我是重複包含了標頭檔案,那有什麼危害麼?像上面的三個函式宣告,在C語言程式中宣告兩次也沒有問題,對於具有External Linkage的函式,宣告任意多次也都代表同一個函式。在C語言專案中重複包含標頭檔案有以下問題:

    一是使預處理的速度變慢了,要處理很多本來不需要處理的標頭檔案。二是如果有互相包含的情況,預處理器就陷入死迴圈了(不過現在編譯器都會規定一個包含層數的上限)。三是標頭檔案裡有些C語言程式碼不允許重複出現,雖然變數和函式允許多次宣告(只要不是多次定義就行),但標頭檔案裡有些C語言程式碼是不允許多次出現的,比如typedef型別定義和結構體Tag定義等,在一個程式檔案中只允許出現一次。還有一個問題,為什麼不直接包含 .c 檔案呢?

    我在 main.c 檔案裡直接 #include “fun.c” 不更方便嗎?當然,這樣的C語言程式碼編譯也能透過,可是以後要是又有一個模組需要用到 fun.c 中定義的函式呢?再包含一次 fun.c ?這樣不就相當於 add() 函式有多處定義了嗎?這樣在程式連結階段就會有麻煩,或者根本無法生成可執行程式。如果包含的是標頭檔案,那無論包含多少次,add() 函式也只有一處定義,連結是不會有問題的了。

  • 2 # 大學生程式設計指南

    從事嵌入式開發多年,對於C語言使用的頻率比較多,現在講講C語言在平時程式設計工作中經常出現的一些問題,就以樓主的題目為切入點分析歸納下,分享給正在使用或者學習C語言的小夥伴

    C語言標頭檔案有什麼用處

    在平時專案開發過程中特別是幾個專案組在一起工作的時候,有的時候程式碼不是完全開放的,這個時候標頭檔案和庫的作用就體現出來了,在標頭檔案中可以看到這個模組使用的結構體,以及靜態變數或者定義的一些宏,最主要的看到這個模組使用的函式列表,同時有些關鍵函式的功能還會在標頭檔案裡面做出說明,通常在專案推進過程中就可以透過標頭檔案呼叫庫裡面的函式,從而完成單元測試。

    剛才說的標頭檔案是自己設計的,這種在平時的程式設計過程中使用的場景還是非常多,在引用標頭檔案的時候需要注意要寫清楚標頭檔案所在的目錄,避免呼叫的時候找不到標頭檔案,還有一些標頭檔案屬於系統自帶的,比如常見的printf函式就是呼叫的系統函式,透過引用

    stdio.h

    就可以使用printf函式列印東西了,有時候發現不帶標頭檔案有些系統函式也能被呼叫起來,主要C語言比較靈活,這種一般在編譯的時候會處警告,搞不影響編譯透過,C語言的編譯通常來講比較隨意,所以在執行過程中可能出現崩潰現象,透過編譯不一定能夠發現。

    所以後續的C++加強了語法檢查,一般在初學c++的泛型程式設計都會有一種壓抑感覺,這是由於C++語法特性決定的,這種程式語言在嵌入式開發過程中使用的也是比較多。

    使用C語言標頭檔案需要注意事項

    標頭檔案的裡面主要宣告一些函式列表,定義一些宏,還會定義一些核心結構體,還會有一些靜態全域性變數,標頭檔案中儘量不要使用全域性變數,因為全域性變數在管理上會顯得麻煩很多,增加出現問題的機率。

    標頭檔案在編譯的時候裡面的宏都會舒展開,為了防止一個檔案被包含多次就會在標頭檔案的開始位置設定#ifndef 這種字眼就是為了避免重複引用。當然在實際的開發過程中標頭檔案設定成什麼樣子還和程式設計能力水平有一定的關係,在模組設計過程中講究的高內聚低耦合,在模組內部使用的函式就不要暴露在標頭檔案中,防止外來的操作對模組的資料造成破壞,所以在設計標頭檔案的時候暴露在外部的函式列表是深思熟慮的,很多初學者在玩標頭檔案的時候甚至要把所有的函式都搬上去了,顯得非常沒有層次感,而且只要在標頭檔案宣告的函式都要標註上清晰的註釋,這樣子在別人呼叫模組函式的時候能夠很輕鬆的知道這個函式的意思。

  • 中秋節和大豐收的關聯?
  • 資料鏈,什麼意思?