最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言編程之預(yù)處理過程與define及條件編譯

 更新時(shí)間:2021年09月17日 15:56:40   作者:Booksort  
這篇文章主要為大家介紹了C語言編程之預(yù)處理過程與define及條件編譯,文中通過圖文及示例代碼方式作了詳細(xì)的解釋,有需要的朋友可以借鑒參考下

這張圖描述了從源文件到可執(zhí)行文件的整體步驟

在這里插入圖片描述

這張圖展示了大體上步驟。

在這里插入圖片描述

從代碼到運(yùn)行環(huán)境,編譯器提供了翻譯環(huán)境。在一個(gè)程序中,會(huì)存在多個(gè)文件 ,而每個(gè)源文件都會(huì)單獨(dú)經(jīng)過編譯器處理。

在這里插入圖片描述

預(yù)編譯:
1,會(huì)將#include等頭文件所包含的內(nèi)容,庫函數(shù)全部拷貝過來
2,代碼中注釋的刪除
3,由#define所定義的符號(hào)全部替換進(jìn)代碼中
對(duì)預(yù)處理指令的操作

編譯:把C代碼翻譯成匯編代碼
1,語法分析(判斷是否存在語言的語法錯(cuò)誤而造成無法編譯)
2,詞法分析
3,語義分析(分析每句代碼的意思)
4,符號(hào)匯總(會(huì)將整個(gè)程序中的全局符號(hào)進(jìn)行匯總)

匯編
1,形成符號(hào)表

在這里插入圖片描述

一個(gè)程序,兩個(gè)文件test.c與add.c,在test.c中,有

extern int add(int x,int y);//聲明對(duì)該函數(shù)引用,在其他文件中找該函數(shù)。

在匯編時(shí),各個(gè)文件都會(huì)形參函數(shù)符號(hào)表,但extern并不會(huì)形成地址標(biāo)記,只是一個(gè)0x00。

鏈接:合并段表
符號(hào)表的合并與重定位檢查各個(gè)函數(shù)及其定義聲明

在這里插入圖片描述

名示常量#define

define的預(yù)處理指令

#define MACRO substitution
預(yù)處理指令 宏 替換體

宏只是起到替換作用,在替換過程中不產(chǎn)生任何運(yùn)算
舉個(gè)例子

#define SUM 2+2
int num = SUM * SUM;

不了解的人可能會(huì)認(rèn)為是
num=44;
但,實(shí)際是替換作用
num=2+22+2;
這就是宏只起到替換作用的意思。

再來介紹一個(gè)原理性概念

記號(hào)
從技術(shù)角度來看,可以把宏的替換體看作是記號(hào)型字符串。而不是字符型字符串。在C預(yù)處理器記號(hào)是宏定義的替換體的中單獨(dú)的“詞”,用空白把詞分開。例如:

#define FOUR 2*2
#define FOURS 2 * 2

這兩個(gè)對(duì)于預(yù)處理器要看預(yù)處理器把這個(gè)替換體看成什么。如果是字符型字符串,這空格也會(huì)是字符串的一部分。但如果是記號(hào)型字符串,空格就會(huì)被認(rèn)為是分隔符,就和2*2是一個(gè)意思??傊淳幾g器的規(guī)則。
總結(jié)一下

如果編譯器理解替換體是字符型字符串,那么空格就會(huì)被認(rèn)為是字符串的一部分
2 * 2就和2*2不是一個(gè)意思。
如果編譯器理解為記號(hào)型字符串,那么空格就會(huì)被認(rèn)為只是分隔符,并不影響??崭癫凰闾鎿Q體的一部分
2 * 2和2乘2則是一個(gè)意思。

重定義常量

假設(shè)把MAX設(shè)為30,在文件中又把它重新定義為10.這個(gè)過程叫重定義常量但不同的標(biāo)準(zhǔn)有不同的規(guī)則。有一些允許重定義,但是會(huì)報(bào)警。ANSI標(biāo)準(zhǔn)則采用,只有新舊定義完全相同才允許重定義。
完全相同意味著替換體中必須記號(hào)完全相同,順序也必須相同 。

#define MAX 2 * 3
#define MAX 2 * 3

這才允許

#define MAX 2 * 3
#define MAX 2*3

這不符合那個(gè)標(biāo)準(zhǔn)。(雖然我不知道這個(gè)標(biāo)準(zhǔn)的重定義有什么用,我比較菜)
注:根據(jù)一個(gè)大佬的建議,這類代碼非常致命,非常不好,最好不使用。

在#define中使用參數(shù)

在#define中也可以創(chuàng)建外形和作用與函數(shù)類似的類函數(shù)宏
帶有函數(shù)的宏可以達(dá)到部分函數(shù)的作用。

#define	SQUARE(X) X*X
mul=SQUARE(2);

與函數(shù)調(diào)用有些相似。
同時(shí)最好使用足夠多的括號(hào)去確保運(yùn)算和結(jié)合性的正確。

mul=SQUARE(x++)

則會(huì)造成運(yùn)算不符合要求。

用宏參數(shù)創(chuàng)建字符串:#運(yùn)算符

#define PSQRA(X) printf("X is %d\n",((X)*(X));
#define PSQRB(X) printf("#X" is %d\n",((X)*(X));

這兩個(gè)是可以打印出不同的效果
#作為一個(gè)預(yù)處理運(yùn)算符,可以把記號(hào)轉(zhuǎn)換成字符串,如果X是一個(gè)宏形參,那么#X就是“X”的字符串的形參名。

這叫字符串化

int y=50;
PSQRA(y)
X is 2500
PSQRB(Y)
y is 2500
PSQRA(2+4)
X is 36
PSQRB(2+4)
2+4 is 36

這就是區(qū)別。

預(yù)處理器粘合劑:##運(yùn)算符

#運(yùn)算符可以作用于宏的替換體
而##運(yùn)算符也可以作用。

#define NUMBER(n) X##n
NUMBER(4)可展開為x4

例如

#include <stdio.h>
#define XNAME(N) x##N
#define PRINT(N) pritnf("x"#N"=%d\n",x##N);
int main(void)
{
	int XNAME(1) = 10;//x1=10
	int XNAME(2) = 20;//x2=10
	int x3 = 0;
	PRINT(1);//printf("x1=%d",x1);
	PRINT(2);//printf("x2=%d",x2);
	PRINT(3);//printf("x3=%d",x3);
}

在這里插入圖片描述

變參宏:… 和_ _ VAG_ARGS_ _

一些函數(shù)可以接受數(shù)量可變的參數(shù)(就是沒有固定傳遞的參數(shù)的數(shù)量,如printf()和scanf())。而宏也可以擁有這樣的能力。

#define PR(...) printf(_ _VAG_ARGS_ _)
PR("HELLO WORLD");//printf("HELLO WORLD");
PR("x1=%d,x2=%d",10,20);//printf(""x1=%d,x2=%d",10,20);

相當(dāng)于這樣的效果。
省略號(hào)只能代替最后的宏參數(shù)。不能在省略號(hào)加其他參數(shù)。

#define PR(x,...,y) #x #_ _VAG_ARGS_ _ #y

是不被允許的。

宏與函數(shù)

有相當(dāng)一部分的宏可以起到和函數(shù)一樣的效果,但到底該怎么選呢?
宏和函數(shù)可以達(dá)到同樣效果。宏比函數(shù)要簡(jiǎn)單一些,同時(shí),在編譯器的消耗時(shí)間也要遠(yuǎn)小于函數(shù)。但是稍有不慎就會(huì)產(chǎn)生一些副作用,導(dǎo)致結(jié)果不可預(yù)測(cè)。
宏與函數(shù)的比較實(shí)際上就是關(guān)于時(shí)間與空間的比較。

宏在預(yù)編譯的時(shí)候會(huì)生成內(nèi)聯(lián)代碼,也就是會(huì)在程序中替換生成語句。如果調(diào)用20次,則會(huì)在程序中插入20行代碼。

但如果調(diào)用函數(shù)20次,函數(shù)也只有一份副本,節(jié)省了相當(dāng)一部分空間。但執(zhí)行函數(shù)時(shí),要調(diào)用,再執(zhí)行,再返回,遠(yuǎn)比宏插入內(nèi)聯(lián)語句消耗的時(shí)間要多。

宏較函數(shù)也存在缺陷

  • 當(dāng)宏較大時(shí)會(huì)增加代碼長(zhǎng)度。
  • 宏是無法調(diào)試(在預(yù)編譯的時(shí)候就已完成替換),可能會(huì)出現(xiàn)問題。
  • 宏由于不要求類型,會(huì)造成不嚴(yán)謹(jǐn)(這也是對(duì)于函數(shù)的一個(gè)好處,函數(shù)傳參會(huì)要求參數(shù)類型,而宏只會(huì)將參數(shù)當(dāng)作字符串處理,只要是int或float類型都可以)
  • 宏可能會(huì)帶來運(yùn)算符優(yōu)先級(jí)的問題,使運(yùn)算不可預(yù)測(cè)。

自己按照情況去使用。如果使用宏容易出現(xiàn)副作用,那還是調(diào)用函數(shù)吧。

但要記住以下幾點(diǎn)

1,記住宏名中不允許有空格,但在替換字符串中可以有空格。ANSI C允許在參數(shù)列表中使用空格。

2,用括號(hào)把宏的參數(shù)和替換體括起來,正確展開,防止出現(xiàn)副作用。

3,一般用大寫字母表示宏常量,一般不全大寫表示宏函數(shù)

4,如果用宏來加快函數(shù)的運(yùn)行速度,要先確定宏和函數(shù)之間是否有差距。且,如果只使用一次那對(duì)速度加快影響不大。最好在多重嵌套中使用。

預(yù)處理指令

當(dāng)編譯器碰上#include 指令時(shí),會(huì)查看后面文件名并把內(nèi)容添加到當(dāng)前文件中。

#include <stdio.h>//查找系統(tǒng)目錄文件
#include "mtfile.h"http://查找當(dāng)前工作目錄
#include "/usr/biff/file.h"http://查找/usr/biff/目錄

不同的系統(tǒng)有不同的規(guī)則,但<>與“”的規(guī)則是不變的。

通過頭文件的引用,我們才能使用各種函數(shù)。頭文件中有各種函數(shù)的聲明。再通過庫文件去調(diào)用函數(shù)的原型。

#undef指令

可以通過該指令去向之前#define定義的宏

#include <stdio.h>
#define MAX 10
#undef MAX
int main(void)
{
	printf("%d", MAX);
}

在這里插入圖片描述

直接報(bào)錯(cuò)
#undef可以取消,某個(gè)宏的定義,可以用用來防止某個(gè)宏被重復(fù)定義,造成錯(cuò)誤。

從C預(yù)處理器的角度看已定義

預(yù)處理器在處理標(biāo)識(shí)符時(shí)遵循相同規(guī)則。當(dāng)預(yù)處理器發(fā)現(xiàn)一個(gè)標(biāo)識(shí)符時(shí),會(huì)將其當(dāng)作已定義或未定義。而這里的已定義是由預(yù)處理器決定。如果該標(biāo)識(shí)符是由define定義的且沒有undef取消,那就是已定義。如果是定義的某個(gè)全局變量,那就是未定義(對(duì)預(yù)處理器而言)。

#define定義的宏的作用域從文件開頭開始,延申至文件結(jié)尾或者遇到#undef取消定義,如果跨文件使用,那使用的位置要在#include引用的文件后。

條件編譯

就跟條件判斷語句有著類似的意思。

#ifdef , #else , #endif

舉個(gè)例子

#include <stdio.h>
#define MAX 10
#undef MAX
#ifdef MAX
	#include <string.h>
	#define MIN 10
#endif // 
int main(void)
{
	printf("%d", MIN);
}

在這里插入圖片描述

結(jié)果就是這個(gè)。
但屏蔽#undef

#include <stdio.h>
#define MAX 10
//#undef MAX
#ifdef MAX
	#include <string.h>
	#define MIN 10
#endif // 
int main(void)
{
	printf("%d", MIN);
}

在這里插入圖片描述

可以運(yùn)行。
條件編譯指令與條件判斷語句類似。
只不過,條件判斷語句是判讀是否執(zhí)行,
二條件編譯指令是判斷是否進(jìn)行預(yù)編譯。
#endif用來結(jié)束該指令的范圍
再引入一個(gè)指令

#ifndef DEBUG

如果DEBUG未定義就執(zhí)行編譯,如果已定義就不執(zhí)行。

還有這幾個(gè)指令,非常接近條件判斷語句

#if ,#elif ,#else

#if和#elif與if和else if類似。但它們的后面接整形常量表達(dá)式。
0為假,非0為真
都是判斷是否進(jìn)行預(yù)編譯

可以通過條件編譯指令去防止某些文件被多次調(diào)用導(dǎo)致問題出現(xiàn)

#ifndef _FILE_H
#define _FILE_H
文件內(nèi)容
。
。
#endif

或者直接使用

#pragma once
//可以保證文件只是使用一次

offsetof函數(shù)

size_t offsetof( structName, memberName );

用于測(cè)算結(jié)構(gòu)體成員相對(duì)于起始位置的偏移量

實(shí)現(xiàn)

#define OFFSETOF(structName,memberName) (int)&(((struct structName*)0)->memberName)

從0地址處,開始向成員訪問再取地址在強(qiáng)轉(zhuǎn)成整形。

以上就是C語言編程之預(yù)處理過程與define及條件編譯的詳細(xì)內(nèi)容,更多關(guān)于C語言預(yù)處理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言一級(jí)指針二級(jí)指針和三級(jí)指針區(qū)別及使用詳解

    C語言一級(jí)指針二級(jí)指針和三級(jí)指針區(qū)別及使用詳解

    這篇文章主要為大家介紹了C語言一級(jí)指針二級(jí)指針和三級(jí)指針,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • C語言高斯消元法的使用詳解

    C語言高斯消元法的使用詳解

    本篇文章是對(duì)C語言中高斯消元法的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C語言實(shí)現(xiàn)修改文本文件中特定行的實(shí)現(xiàn)代碼

    C語言實(shí)現(xiàn)修改文本文件中特定行的實(shí)現(xiàn)代碼

    最近由于項(xiàng)目需要實(shí)現(xiàn)修改文件的功能,所以,博主認(rèn)真查閱了一些資料,但是,很遺憾,并沒有太多的收獲
    2013-06-06
  • C++實(shí)現(xiàn)LeetCode(200.島嶼的數(shù)量)

    C++實(shí)現(xiàn)LeetCode(200.島嶼的數(shù)量)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(200.島嶼的數(shù)量),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++ 使用VS Code運(yùn)行程序時(shí)終端輸出中文亂碼的解決辦法

    C++ 使用VS Code運(yùn)行程序時(shí)終端輸出中文亂碼的解決辦法

    這篇文章主要介紹了C++ 使用VS Code運(yùn)行程序時(shí)終端輸出中文亂碼的解決辦法 ,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • C語言示例講解for循環(huán)的用法

    C語言示例講解for循環(huán)的用法

    初學(xué)C語言,常常遇到for循環(huán)中嵌套個(gè)for循環(huán),初學(xué)者對(duì)于這種形式總是一知半解,這次我就整理了常見的for循環(huán)嵌套for循環(huán)的題目,我們一起爭(zhēng)取一舉拿下這類題。學(xué)廢他們,以后再見到就不怕啦!每天都要學(xué)一點(diǎn)呀。加油,奮斗的我們
    2022-06-06
  • C語言單鏈表遍歷與求和示例解讀

    C語言單鏈表遍歷與求和示例解讀

    我們?cè)趯W(xué)習(xí)編程的過程中,雖然有些語法很簡(jiǎn)單,但是我們還是要做多題。不做題是發(fā)現(xiàn)不了問題的,發(fā)現(xiàn)問題我們就可以“對(duì)癥下藥”,進(jìn)行查漏補(bǔ)缺了。刷題可以先從簡(jiǎn)單題開始刷,熟練之后再做一些可以提升自己能力的題
    2022-07-07
  • C++?OpenCV實(shí)現(xiàn)之實(shí)現(xiàn)紅綠燈識(shí)別

    C++?OpenCV實(shí)現(xiàn)之實(shí)現(xiàn)紅綠燈識(shí)別

    本文以實(shí)現(xiàn)行車過程當(dāng)中的紅綠燈識(shí)別為目標(biāo),核心的內(nèi)容包括:OpenCV輪廓識(shí)別原理以及OpenCV紅綠燈識(shí)別的實(shí)現(xiàn)具體步驟,感興趣的可以了解一下
    2022-08-08
  • C++數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)鄰接表

    C++數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)鄰接表

    這篇文章主要為大家詳細(xì)介紹了C++數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)鄰接表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C++中this指針的理解與作用詳解

    C++中this指針的理解與作用詳解

    這篇文章主要給大家介紹了關(guān)于C++中this指針的理解與作用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12

最新評(píng)論

滦南县| 来凤县| 深水埗区| 广西| 阿拉善左旗| 肥城市| 淮南市| 丹江口市| 甘南县| 高密市| 南充市| 新沂市| 宜君县| 同仁县| 邓州市| 府谷县| 沭阳县| 平陆县| 延川县| 郎溪县| 井冈山市| 屯留县| 赣州市| 呼图壁县| 五大连池市| 武穴市| 北流市| 积石山| 台北县| 苍山县| 鄂托克前旗| 荥阳市| 山西省| 彝良县| 佛山市| 灵丘县| 郯城县| 葫芦岛市| 无锡市| 额尔古纳市| 沈丘县|