日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【C语言重点难点精讲】C语言预处理

發(fā)布時間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C语言重点难点精讲】C语言预处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 一:C/C++程序程序編譯過程
    • (1)預(yù)處理
    • (2)編譯
    • (3)匯編
    • (4)鏈接
  • 二:宏定義
    • (1)數(shù)值宏常量
    • (2)字符串宏常量
    • (3)使用宏充當(dāng)注釋
    • (4)使用宏充當(dāng)表達(dá)式
  • 三:宏其他
  • 四:條件編譯
    • (1)#ifdef和#ifndef
    • (2)#if
    • (3)文件包含

一:C/C++程序程序編譯過程

(1)預(yù)處理

  • 預(yù)處理主要包括宏定義,文件包含,條件編譯,去注釋
  • 輸入gcc -E hello.c -o hello.i,其中選項E作用是讓gcc在預(yù)處理后停止編譯

(2)編譯

  • 此階段,gcc檢查代碼的規(guī)范性,是否具有語法錯誤
  • 輸入gcc -S hello.i -o hello.s,即可將預(yù)處理里的結(jié)果繼續(xù)繼續(xù)編譯

(3)匯編

  • 編譯階段無誤后,進(jìn)入?yún)R編,將“.s”文件轉(zhuǎn)化為“.o”二進(jìn)制文件
  • 輸入gcc -c hello.s -o hello.o,即可將編譯停止在此階段


(打開二進(jìn)制文件使用od命令)

(4)鏈接

  • 此階段,將目標(biāo)文件與系統(tǒng)庫進(jìn)行鏈接生成可執(zhí)行文件。
  • 輸入gcc hello.o -o hello,則完成編譯

選項描述
-E進(jìn)行預(yù)處理,不進(jìn)行編譯,匯編和鏈接
-S進(jìn)行編譯,不進(jìn)行匯編和鏈接
-c進(jìn)行匯編,不進(jìn)行鏈接
-o鏈接
static采用靜態(tài)鏈接
-g生成調(diào)試信息
-shared使用動態(tài)庫
-O0無優(yōu)化
-O1默認(rèn)優(yōu)化級別
-O3優(yōu)化最高
-w不生成警告信息
-Wall生成所有警告信息

二:宏定義

(1)數(shù)值宏常量

(2)字符串宏常量

(3)使用宏充當(dāng)注釋

先去掉注釋,再進(jìn)行宏替換

(4)使用宏充當(dāng)表達(dá)式

#define SUM(X) (X)+(X)int main() {printf("%d\n", SUM(10));return 0; }

需要注意使用宏充當(dāng)多條語句時有可能出現(xiàn)一些潛在的問題,比如下面這個宏有兩條語句,但是在if后面如果直接跟上宏而沒有帶花括號就會出現(xiàn)問題

#define INT_VAL(a,b) a=0;b=0

如果需要宏替換大塊語句,可以使用do-while(0)結(jié)構(gòu)

#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來結(jié)束宏的作用

int main() { #define M 10//從這里開始printf("main:%d\n", M);printf("main:%d\n", M);printf("main:%d\n", M); #undef M//到這里結(jié)束printf("main:%d\n", M);//錯誤return 0;}

第三:有如下宏定義

#define foo(4+foo)

按照一般理解 + foo)會展開成(4 + (4 + foo)),然后一直展開下去,直至內(nèi)存耗盡。但是,預(yù)處理器采取的策略是只展開一次 。也就是說,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); }

宏只是字符串替換,并沒有計算能力,所以最后的結(jié)果是(2+1+1)*2+1/2

四:條件編譯

(1)#ifdef和#ifndef

  • ifdef:判定宏是否被定義,宏為真假沒有關(guān)系,傾向于要定義
  • ifndef:判定宏是否沒有定義,宏為真假沒有關(guān)系,傾向于不要定義

下面的例子中沒有定義PRINT,所以代碼只會保留#else這一部分,代碼在預(yù)處理時直接被裁掉

int main() { #ifdef PRINT//實際未定義printf("hello\n"); #elseprintf("no print\n"); #endifreturn 0; }


如果PRINT被定義了,然后換成ifndef,效果也是一樣的

#define PRINT//宏被定義 int main() { #ifndef PRINT//如果沒有定義printf("hello\n"); #elseprintf("no print\n"); #endifprintf("continue\n");return 0; }

(2)#if

  • #if:判定是否存在,以及是否為真,傾向于存在且為真

如下宏P(guān)RINT,被定義了但是為0,因此會輸出#else里面內(nèi)容

# define PRINT 0//定義了但是為假int main() { #if PRINTprintf("hello\n"); #else PRINTprintf("other"); #endifreturn 0; }

#if可以進(jìn)行多分支控制

#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; }


如果要判斷多個宏,可以這樣進(jìn)行

#define Condition1 1 #define Condition2 0int main() { #if Condition1 && Condition2printf("all\n"); #elseprintf("other\n"); #endifreturn 0; }

(3)文件包含

有一個頭文件test.h,為了防止其被重復(fù)包含,我們通常的做法就是,在該文件內(nèi)寫上這樣的語句。現(xiàn)在看來效果很明顯,在第一次包含時#define會被立即被定義,第n次包含時由于_TEST_H被定義了,所以就不會執(zhí)行

#ifndef _TEST_H #define _TEST_H#endif // !_TEST_H
  • 其實頭文件在展開時,本質(zhì)就是將其內(nèi)容經(jīng)過一些處理后拷貝到了目標(biāo)源文件

總結(jié)

以上是生活随笔為你收集整理的【C语言重点难点精讲】C语言预处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。