C/C++編程筆記:C語言預(yù)處理命令是什么?不要以為你直接寫#就行!
很多小伙伴在自己寫代碼的時(shí)候,已經(jīng)多次使用過#include命令。使用庫函數(shù)之前,應(yīng)該用#include引入對(duì)應(yīng)的頭文件。其實(shí)這種以#號(hào)開頭的命令稱為預(yù)處理命令。

C語言源文件要經(jīng)過編譯、鏈接才能生成可執(zhí)行程序:
1) 編譯(Compile)會(huì)將源文件(.c文件)轉(zhuǎn)換為目標(biāo)文件。對(duì)于 VC/VS,目標(biāo)文件后綴為.obj;對(duì)于GCC,目標(biāo)文件后綴為.o。
編譯是針對(duì)單個(gè)源文件的,一次編譯操作只能編譯一個(gè)源文件,如果程序中有多個(gè)源文件,就需要多次編譯操作。
2) 鏈接(Link)是針對(duì)多個(gè)文件的,它會(huì)將編譯生成的多個(gè)目標(biāo)文件以及系統(tǒng)中的庫、組件等合并成一個(gè)可執(zhí)行程序。
關(guān)于編譯和鏈接的過程、目標(biāo)文件和可執(zhí)行文件的結(jié)構(gòu)、.h 文件和 .c 文件的區(qū)別,我們將在后期專題中講解。
在實(shí)際開發(fā)中,有時(shí)候在編譯之前還需要對(duì)源文件進(jìn)行簡單的處理。例如,我們希望自己的程序在 Windows 和 Linux 下都能夠運(yùn)行,那么就要在 Windows 下使用 VS 編譯一遍,然后在 Linux 下使用 GCC 編譯一遍。但是現(xiàn)在有個(gè)問題,程序中要實(shí)現(xiàn)的某個(gè)功能在 VS 和 GCC 下使用的函數(shù)不同(假設(shè) VS 下使用 a(),GCC 下使用 b()),VS 下的函數(shù)在 GCC 下不能編譯通過,GCC 下的函數(shù)在 VS 下也不能編譯通過,怎么辦呢?

這就需要在編譯之前先對(duì)源文件進(jìn)行處理:如果檢測(cè)到是 VS,就保留 a() 刪除 b();如果檢測(cè)到是 GCC,就保留 b() 刪除 a()。
這些在編譯之前對(duì)源文件進(jìn)行簡單加工的過程,就稱為預(yù)處理(即預(yù)先處理、提前處理)。
預(yù)處理主要是處理以#開頭的命令,例如#include <stdio.h>等。預(yù)處理命令要放在所有函數(shù)之外,而且一般都放在源文件的前面。
預(yù)處理是C語言的一個(gè)重要功能,由預(yù)處理程序完成。當(dāng)對(duì)一個(gè)源文件進(jìn)行編譯時(shí),系統(tǒng)將自動(dòng)調(diào)用預(yù)處理程序?qū)υ闯绦蛑械念A(yù)處理部分作處理,處理完畢自動(dòng)進(jìn)入對(duì)源程序的編譯。
編譯器會(huì)將預(yù)處理的結(jié)果保存到和源文件同名的.i文件中,例如 main.c 的預(yù)處理結(jié)果在 main.i 中。和.c一樣,.i也是文本文件,可以用編輯器打開直接查看內(nèi)容。
C語言提供了多種預(yù)處理功能,如宏定義、文件包含、條件編譯等,合理地使用它們會(huì)使編寫的程序便于閱讀、修改、移植和調(diào)試,也有利于模塊化程序設(shè)計(jì)。

實(shí)例
下面我們舉個(gè)例子來說明預(yù)處理命令的實(shí)際用途。假如現(xiàn)在要開發(fā)一個(gè)C語言程序,讓它暫停 5 秒以后再輸出內(nèi)容,并且要求跨平臺(tái),在 Windows 和 Linux 下都能運(yùn)行,怎么辦呢?
這個(gè)程序的難點(diǎn)在于,不同平臺(tái)下的暫停函數(shù)和頭文件都不一樣:
Windows 平臺(tái)下的暫停函數(shù)的原型是void Sleep(DWORD dwMilliseconds)(注意 S 是大寫的),參數(shù)的單位是“毫秒”,位于??頭文件。
Linux 平臺(tái)下暫停函數(shù)的原型是unsigned int sleep (unsigned int seconds),參數(shù)的單位是“秒”,位于??頭文件。
不同的平臺(tái)下必須調(diào)用不同的函數(shù),并引入不同的頭文件,否則就會(huì)導(dǎo)致編譯錯(cuò)誤,因?yàn)?Windows 平臺(tái)下沒有 sleep() 函數(shù),也沒有 <unistd.h> 頭文件,反之亦然。這就要求我們?cè)诰幾g之前,也就是預(yù)處理階段來解決這個(gè)問題。請(qǐng)看下面的代碼:
#include<stdio.h>
//不同的平臺(tái)下引入不同的頭文件
#if_WIN32//識(shí)別windows平臺(tái)
#include<windows.h>
#elif__linux__//識(shí)別linux平臺(tái)
#include<unistd.h>
#endif
intmain(){
//不同的平臺(tái)下調(diào)用不同的函數(shù)
? ? #if_WIN32//識(shí)別windows平臺(tái)
Sleep(5000);
? ? #elif__linux__//識(shí)別linux平臺(tái)
sleep(5);
? ? #endif
puts("http://c.biancheng.net/");
return0;
}
#if、#elif、#endif 就是預(yù)處理命令,它們都是在編譯之前由預(yù)處理程序來執(zhí)行的。這里我們不討論細(xì)節(jié),只從整體上來理解。
對(duì)于 Windows 平臺(tái),預(yù)處理以后的代碼變成:
#include<stdio.h>
#include<windows.h>
intmain(){
Sleep(5000);
puts("http://c.biancheng.net/");
return0;
}
對(duì)于 Linux 平臺(tái),預(yù)處理以后的代碼變成:
#include<stdio.h>
#include<unistd.h>
intmain(){
sleep(5);
puts("http://c.biancheng.net/");
return0;
}
你看,在不同的平臺(tái)下,編譯之前(預(yù)處理之后)的源代碼都是不一樣的。這就是預(yù)處理階段的工作,它把代碼當(dāng)成普通文本,根據(jù)設(shè)定的條件進(jìn)行一些簡單的文本替換,將替換以后的結(jié)果再交給編譯器處理。
現(xiàn)在,你懂了嗎?
微信公眾號(hào):C語言編程學(xué)習(xí)基地,學(xué)習(xí)C/C++編程知識(shí),歡迎關(guān)注筆者哦~

學(xué)習(xí)C/C++編程知識(shí),提升C/C++編程能力,歡迎關(guān)注UP一起來成長!
另外,UP在主頁上傳了一些學(xué)習(xí)C/C++編程的視頻教程,有興趣或者正在學(xué)習(xí)的小伙伴一定要去看一看哦!會(huì)對(duì)你有幫助的~