我們常說的「編譯器」實際指編譯工具鏈,包含四個階段:
#include、#define 等預處理指令.obj/.o)| 階段 | 外部函數處理 |
|---|---|
| 編譯階段 | 僅需聲明(通常在頭文件),不需要函數實體 |
| 鏈接階段 | 必須找到函數實體定義,否則報錯「undefined reference」 |
.h 和 .c 文件名無任何強制關聯.c 文件為編譯單元,連接器以目標文件為單元.c 文件(含 main 入口).c 文件,遇 #include 遞歸展開頭文件.obj/.o).exe/a.out).c 包含 → 多份函數代碼 → 鏈接報錯「multiple definition」stdio.h:用戶只需知道 printf 原型,無需關心實現a.c 是否需要 #include "a.h"?// a.h
void foo();
// a.c
#include "a.h" // 這行是否多余?
void foo() { return; }
// main.c
#include "a.h"
int main() { foo(); return 0; }
a.c 內部函數互調,包含頭文件可避免聲明順序問題(C 語言要求先聲明後使用)。許多項目將其作為編碼規範。.h 與 .c 有任何關聯。#include 只是文本展開,與文件名無關。.h 和 .c 皆為文本文件,後綴無本質區別#include "xx.h" = 將 xx.h 內容原封不動插入當前行# 編譯生成目標文件
gcc -c a.c -o a.o
gcc -c b.c -o b.o
# 打包為靜態庫
ar rcs libmylib.a a.o b.o
# 使用庫
gcc main.c -L. -lmylib -o main
.so/.dll)LD_LIBRARY_PATH、rpath)extern 變量聲明#ifndef HEADER_H #define HEADER_H ... #endif