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

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

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

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

在這里插入圖片描述

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

在這里插入圖片描述

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

在這里插入圖片描述

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

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

匯編
1,形成符號表

在這里插入圖片描述

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

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

在匯編時,各個文件都會形參函數(shù)符號表,但extern并不會形成地址標記,只是一個0x00。

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

在這里插入圖片描述

名示常量#define

define的預處理指令

#define MACRO substitution
預處理指令 宏 替換體

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

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

不了解的人可能會認為是
num=44;
但,實際是替換作用
num=2+22+2;
這就是宏只起到替換作用的意思。

再來介紹一個原理性概念

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

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

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

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

重定義常量

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

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

這才允許

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

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

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

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

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

與函數(shù)調用有些相似。
同時最好使用足夠多的括號去確保運算和結合性的正確。

mul=SQUARE(x++)

則會造成運算不符合要求。

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

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

這兩個是可以打印出不同的效果
#作為一個預處理運算符,可以把記號轉換成字符串,如果X是一個宏形參,那么#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ū)別。

預處理器粘合劑:##運算符

#運算符可以作用于宏的替換體
而##運算符也可以作用。

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

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

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

是不被允許的。

宏與函數(shù)

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

宏在預編譯的時候會生成內聯(lián)代碼,也就是會在程序中替換生成語句。如果調用20次,則會在程序中插入20行代碼。

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

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

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

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

但要記住以下幾

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

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

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

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

預處理指令

當編譯器碰上#include 指令時,會查看后面文件名并把內容添加到當前文件中。

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

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

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

#undef指令

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

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

在這里插入圖片描述

直接報錯
#undef可以取消,某個宏的定義,可以用用來防止某個宏被重復定義,造成錯誤。

從C預處理器的角度看已定義

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

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

條件編譯

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

#ifdef , #else , #endif

舉個例子

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

在這里插入圖片描述

結果就是這個。
但屏蔽#undef

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

在這里插入圖片描述

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

#ifndef DEBUG

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

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

#if ,#elif ,#else

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

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

#ifndef _FILE_H
#define _FILE_H
文件內容
。
。
#endif

或者直接使用

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

offsetof函數(shù)

size_t offsetof( structName, memberName );

用于測算結構體成員相對于起始位置的偏移量

實現(xiàn)

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

從0地址處,開始向成員訪問再取地址在強轉成整形。

以上就是C語言編程之預處理過程與define及條件編譯的詳細內容,更多關于C語言預處理的資料請關注腳本之家其它相關文章!

相關文章

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

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

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

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

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

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

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

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

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

    C++ 使用VS Code運行程序時終端輸出中文亂碼的解決辦法

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

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

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

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

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

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

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

    C++數(shù)據(jù)結構之實現(xiàn)鄰接表

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

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

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

最新評論

溧水县| 大名县| 阳信县| 贡嘎县| 来宾市| 曲麻莱县| 洛宁县| 绵竹市| 红河县| 马山县| 金堂县| 卫辉市| 辉南县| 班玛县| 峨山| 博客| 石泉县| 镇坪县| 巴彦淖尔市| 长葛市| 扶绥县| 雷州市| 礼泉县| 奉化市| 襄汾县| 江孜县| 罗山县| 新营市| 正安县| 孟津县| 宝清县| 阿坝县| 罗田县| 五大连池市| 新竹市| 洪泽县| 中宁县| 临邑县| 那曲县| 苏州市| 确山县|