【C语言重点难点精讲】C语言预处理
文章目錄
- 一:C/C++程序程序編譯過程
- (1)預處理
- (2)編譯
- (3)匯編
- (4)鏈接
- 二:宏定義
- (1)數(shù)值宏常量
- (2)字符串宏常量
- (3)使用宏充當注釋
- (4)使用宏充當表達式
- 三:宏其他
- 四:條件編譯
- (1)#ifdef和#ifndef
- (2)#if
- (3)文件包含
一:C/C++程序程序編譯過程
(1)預處理
- 預處理主要包括宏定義,文件包含,條件編譯,去注釋
- 輸入gcc -E hello.c -o hello.i,其中選項E作用是讓gcc在預處理后停止編譯
(2)編譯
- 此階段,gcc檢查代碼的規(guī)范性,是否具有語法錯誤
- 輸入gcc -S hello.i -o hello.s,即可將預處理里的結果繼續(xù)繼續(xù)編譯
(3)匯編
- 編譯階段無誤后,進入?yún)R編,將“.s”文件轉(zhuǎn)化為“.o”二進制文件
- 輸入gcc -c hello.s -o hello.o,即可將編譯停止在此階段
(打開二進制文件使用od命令)
(4)鏈接
- 此階段,將目標文件與系統(tǒng)庫進行鏈接生成可執(zhí)行文件。
- 輸入gcc hello.o -o hello,則完成編譯
| -E | 進行預處理,不進行編譯,匯編和鏈接 |
| -S | 進行編譯,不進行匯編和鏈接 |
| -c | 進行匯編,不進行鏈接 |
| -o | 鏈接 |
| static | 采用靜態(tài)鏈接 |
| -g | 生成調(diào)試信息 |
| -shared | 使用動態(tài)庫 |
| -O0 | 無優(yōu)化 |
| -O1 | 默認優(yōu)化級別 |
| -O3 | 優(yōu)化最高 |
| -w | 不生成警告信息 |
| -Wall | 生成所有警告信息 |
二:宏定義
(1)數(shù)值宏常量
略
(2)字符串宏常量
略
(3)使用宏充當注釋
先去掉注釋,再進行宏替換
(4)使用宏充當表達式
#define SUM(X) (X)+(X)int main() {printf("%d\n", SUM(10));return 0; }需要注意使用宏充當多條語句時有可能出現(xiàn)一些潛在的問題,比如下面這個宏有兩條語句,但是在if后面如果直接跟上宏而沒有帶花括號就會出現(xiàn)問題
#define INT_VAL(a,b) a=0;b=0如果需要宏替換大塊語句,可以使用do-while(0)結構
#define GIVE_VALUE(a,b) do{a=0;b=0;}while(0)int main() {int x = 10;int y = 20;int flag = 0;scanf("%d", &flag);printf("before:%d,%d\n", x,y);if (flag)GIVE_VALUE(x, y);elsex = 10, y = 20;printf("after:%d,%d\n", x, y);}三:宏其他
第一: 宏定義在文件的任何位置都可以,只要是在你使用這個宏之前定義就可以
void show() { #define M 10printf("show:%d\n", M); } int main() {show();printf("main:%d\n", M);return 0;}第二 可以使用#undef來結束宏的作用
int main() { #define M 10//從這里開始printf("main:%d\n", M);printf("main:%d\n", M);printf("main:%d\n", M); #undef M//到這里結束printf("main:%d\n", M);//錯誤return 0;}第三:有如下宏定義
#define foo(4+foo)按照一般理解 + foo)會展開成(4 + (4 + foo)),然后一直展開下去,直至內(nèi)存耗盡。但是,預處理器采取的策略是只展開一次 。也就是說,foo只會展開成(4 + foo),而展開之后foo的含義就要根據(jù)上下文來確定了。
對于以下的交叉引用,宏體也只會展開一次
#define x(4+y) #define y(2+x)其中x展開成(4+y)->(4+(2*x)),y展開成(2 * x) -> (2 * (4 + y))。
#include <stdio.h> #define N 2 #define M N + 1 #define NUM (M + 1) * M / 2 main() { printf("%d\n", NUM); }宏只是字符串替換,并沒有計算能力,所以最后的結果是(2+1+1)*2+1/2
四:條件編譯
(1)#ifdef和#ifndef
- ifdef:判定宏是否被定義,宏為真假沒有關系,傾向于要定義,
- ifndef:判定宏是否沒有定義,宏為真假沒有關系,傾向于不要定義
下面的例子中沒有定義PRINT,所以代碼只會保留#else這一部分,代碼在預處理時直接被裁掉
int main() { #ifdef PRINT//實際未定義printf("hello\n"); #elseprintf("no print\n"); #endifreturn 0; }
如果PRINT被定義了,然后換成ifndef,效果也是一樣的
(2)#if
- #if:判定是否存在,以及是否為真,傾向于存在且為真
如下宏PRINT,被定義了但是為0,因此會輸出#else里面內(nèi)容
# define PRINT 0//定義了但是為假int main() { #if PRINTprintf("hello\n"); #else PRINTprintf("other"); #endifreturn 0; }#if可以進行多分支控制
#define HELLO 2//注意這里使用的是==,像!=,<,>等可以使用 int main() { #if HELLO==1printf("hello1\n"); #elif HELLO==2printf("hello2\n"); #elif HELLO==3printf("hello3\n"); #elseprintf("other\n"); #endifreturn 0; }
如果要判斷多個宏,可以這樣進行
(3)文件包含
有一個頭文件test.h,為了防止其被重復包含,我們通常的做法就是,在該文件內(nèi)寫上這樣的語句。現(xiàn)在看來效果很明顯,在第一次包含時#define會被立即被定義,第n次包含時由于_TEST_H被定義了,所以就不會執(zhí)行
#ifndef _TEST_H #define _TEST_H#endif // !_TEST_H- 其實頭文件在展開時,本質(zhì)就是將其內(nèi)容經(jīng)過一些處理后拷貝到了目標源文件
總結
以上是生活随笔為你收集整理的【C语言重点难点精讲】C语言预处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python引入导入自定义模块和外部文件
- 下一篇: 基础编程题之因数分解