1. 程式人生 > >C語言程式設計 學習筆記 12.3 多個原始碼檔案、標頭檔案、宣告

C語言程式設計 學習筆記 12.3 多個原始碼檔案、標頭檔案、宣告

我們經常在做“分而治之”的事情(多個.c檔案): 1.main()裡的程式碼太長了適合分成幾個函式 2.一個原始碼檔案太長了適合分成幾個檔案 3.兩個獨立的原始碼檔案不能編譯成可執行的程式

對於(1),我們可以舉以下例子: 有個主函式main.c,有另外一個函式max.c(求最大值)

#include<stdio.h>
int max(int a,int b);
int main(){
	int a=5;
	int b=6;
	printf("%d\n",max(a,b));
	return 0;
}

對於上面直接編譯,系統會報錯:

undefined reference to `max(int, int)’

未定義的max引用

int max(int a,int b){
	return a>b?a:b;
}

對於上面編譯,會說沒有main();

要想將這兩個聯合在一起,需要做如下操作(DEV C++環境下) 檔案-新建-專案-console application-取名叫max-選擇C專案-確定-儲存在剛剛main和max專案的目錄中 然後能在如下介面-專案管理中看到剛剛建立的max,右鍵將自己的兩個cpp/c檔案放入 在這裡插入圖片描述

加入後進行編譯,編譯通過,就可以使用了。

標頭檔案 在剛剛的程式碼中,main函式中事先聲明瞭max:

int max(int a,int b);

如果我們不想將多個函式宣告也寫在主函式中,就像#include<string.h>一樣直接使用,那麼可以自己手寫一個頭檔案,在需要的時候引用它: 1.新建原始檔(devc++會提示你是否在專案中增加新單元,選擇yes,否則就是麻煩一點而已) 2.將我們宣告的函式原型放入其中,並取名,檔案格式是

max.h

然後將其分別在main函式、max函式中include進去

#include "max.h"

編譯通過,可以執行。

全程式碼如下:

//main.cpp
#include <stdio.h>
#include "max.h"

int main(){
	int a=5;
	int b=6;
	printf("%d\n",max(a,b));
	return 0;
}
//max.cpp
#include "max.h"
int max(int a,int b){
	return a>b?a:b;
}
//max.h
int max(int a,int b);

標頭檔案

把函式原型放到一個頭檔案(以.h結尾)中,在需要呼叫這個函式的原始碼檔案(.c/.cpp檔案)中#include這個標頭檔案,就能讓編譯器在編譯的時候知道函式的原型

#include #include是一個編譯預處理指令,和巨集一樣,在編譯之前就處理了 它把那個檔案的全部文字內容原封不動地插入到它所在的地方,所以也不是一定要在.c/.cpp檔案的最前面#include

" "和< > #include有兩種形式來指出要插入的檔案 " "要求編譯器首先在當前目錄(.c/.cpp檔案所在的目錄)尋找這個檔案,如果沒有,到編譯器的指定的目錄去找 < >讓編譯器只在指定的目錄去找 編譯器本身自己知道自己的標準庫標頭檔案在哪裡(string.h、iostream等) 環境變數和編譯器命令列引數也可以指定尋找標頭檔案的目錄

#Include的誤區 #include不是用來引入庫的 stdio.h裡只有printf的原型,printf的程式碼在另外的地方,某個lib(windows)或.a(unix)中 現在的C語言編譯器預設會引入所有的標準庫 #include<stdio.h>只是為了讓編譯器知道printf函式的原型,保證你呼叫時給出的引數值是正確的型別

標頭檔案 在使用和定義這個函式的地方都應該有#include這個標頭檔案 一般的做法是任何.c都有對應的同名的.h,把所有對外公開的函式的原型和全域性變數的宣告都放進去

不對外公開的函式 在函式前面加上static就使得它成為只能在所在的編譯單元中被使用的函式 在全域性變數前面加上static就使得它成為只能在所在的編譯單元中被使用的全域性變數

宣告 如果我想在某檔案中使用一個全域性變數(A檔案中使用B檔案的一個變數) 那麼可以在.h檔案中宣告該變數

extern int gAll;

變數的宣告 int i;是變數的定義 extern int i;是變數的宣告

宣告的定義 宣告是不產生程式碼的東西(函式原型、變數宣告、結構宣告、巨集宣告、列舉宣告、型別宣告、inline函式) 定義是產生程式碼的東西

標頭檔案 只有宣告可以被放在標頭檔案中,否則會造成一個專案中多個編譯單元裡有重名的實體(某些編譯器允許幾個編譯單元中存在同名的函式,或者用weak修飾符來強調這種存在)

重複宣告 同一個編譯單元裡,同名的結構不能被重複宣告 如果你的標頭檔案裡有結構的宣告,很難這個標頭檔案不會再一個編譯單元裡被#include多次 所以需要“標準標頭檔案結構” 上述的意思舉例: 我有max.h和min.h兩個標頭檔案,裡面的內容是這樣:

//max.h
int max(int a,int b);
struct Node{
	int a;
	char *b;
}; 
//min.h
#include "max.h"
//main.cpp
#include <stdio.h>
#include "max.h"
#include "min.h" 

int main(){
	int a=5;
	int b=6;
	printf("%d\n",max(a,b));
	return 0;
}

編譯會報

[Error] redefinition of ‘struct Node’

重複定義了struct node。 這在大型專案中經常會遇到這種情況。

所以這時候需要“標準標頭檔案結構” 在max.h中修改程式碼如下:

#ifndef _MAX_H_
#define _MAX_H_
 
int max(int a,int b);
struct Node{
	int a;
	char *b;
}; 

#endif

再次編譯,編譯成功。

意思是,如果(if)我們沒有定義(ndef)MAX_H(名字自己取,取得特殊一點易於和程式碼內容區分開),那麼系統就幫助我們定義_MAX_H_,並附有下面的程式碼,直到#endif為止

所以在我們#include"min.h"的時候,因為之前已經#include"max.h",並定義了_MAX_H_,所以min的ifndef生效,不發動,直到endif為止。

運用條件編譯和巨集,保證這個標頭檔案在一個編譯單元中只會被#include一次 #pragma once也能起到相同的作用,但並不是所有的編譯器都支援