国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C語言基礎(chǔ)】:預(yù)處理詳解(一)

這篇具有很好參考價值的文章主要介紹了【C語言基礎(chǔ)】:預(yù)處理詳解(一)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

一、預(yù)定義符號

在C語言中設(shè)置了許多的預(yù)定義符號,這些預(yù)定義符號是可以直接使用的,預(yù)定義符號也是在預(yù)處理階段進(jìn)行處理的。

常見的預(yù)定義符號

__FILE__ //進(jìn)?編譯的源文件
__LINE__ //文件當(dāng)前的行號
__DATE__ //文件被編譯的日期
__TIME__ //文件被編譯的時間
__STDC__ //如果編譯器遵循ANSI C,其值為1,否則未定義

【示例】

#include<stdio.h>

int main()
{
	printf("%s\n", __FILE__);
	printf("%s\n", __DATE__);
	printf("%s\n", __TIME__);
	printf("%d\n", __LINE__);
	return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
我們在VS上使用 _ _ STDC _ _ 會發(fā)現(xiàn)顯示未定義,這也就說明VS的編譯器是不完全遵循ANSI C的,為了展示效果,我沒可以在gcc的環(huán)境下查看一下。
【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
在gcc環(huán)境下運(yùn)行可以看到它輸出的是1,這表明gcc環(huán)境下的編譯器是遵循ANSI C的。
預(yù)處理之后我們會發(fā)現(xiàn),前面我們就學(xué)過,程序在預(yù)處理之后會把預(yù)定義指令給替換掉,這里結(jié)果也確實(shí)如此。
【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言

二、#define定義常量

#define一般有兩種應(yīng)用場景:

  1. #define定義常量
  2. #define定義宏

#define定義常量基本語法:

#define name stuff

【示例】

#include<stdio.h>
#define MAX 100
#define STR "hello world"
int main()
{
	int a = MAX;
	printf("%d\n", MAX);
	printf("%s\n", STR);
	return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言

#define定義標(biāo)識符加不加 ; 的區(qū)別:

#include<stdio.h>
#define MAX 100
#define MAX1 100;
int main()
{
	int a = MAX;
	int b = MAX1;
	printf("%d\n", MAX);
	printf("%d\n", MAX1);
	return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
可以看到,MAX1加了分號之后, 之后后面使用的MAX1全都加上了分號,這也就導(dǎo)致了在打印MAX1時報錯,在預(yù)處理之后可以清楚的看到原因(#define把;也替換過來了)。所以一般使用 #define 定義常量時,不要加分號。

三、#define定義宏

#define 機(jī)制包括了?個規(guī)定,允許把參數(shù)替換到文本中,這種實(shí)現(xiàn)通常稱為宏(macro)或定義宏(define macro)。

宏的申明方式

#define name( parament-list ) stuff

parament-list 是?個由逗號隔開的符號表,它們可能出現(xiàn)在stuff中。
注意:參數(shù)列表的左括號必須與name緊鄰,如果兩者之間有任何空白存在,參數(shù)列表就會被解釋為stuff的?部分。

【示例】:利用宏求一個數(shù)的平方

#include<stdio.h>
#define SQURE(x) x * x
int main()
{
	int a = 12;
	int b = SQURE(a);
	printf("%d\n", b);
	return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
因?yàn)閰?shù)是允許替換到文本中的,把a(bǔ)傳給SQURE(a)就相當(dāng)于把程序替換成了a * a, 這里預(yù)處理后也能看到效果。

但是這個宏也存在著一些問題:

int a = 5;
printf("%d\n", SQURE(a + 1));

按照慣性,我們會覺得這個代碼的運(yùn)行結(jié)果會是6 * 6 = 36,但結(jié)果真的會是這樣嗎?
我們來運(yùn)行試一下:
【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
運(yùn)行之后可以發(fā)現(xiàn)結(jié)果等于11,這里就要注意了,宏的參數(shù)是不會參與計(jì)算的,會直接進(jìn)行替換,我們進(jìn)行預(yù)處理生成目標(biāo)文件后可以發(fā)現(xiàn)SQURE(a + 1)替換成了a + 1 * a + 1,而 * 的優(yōu)先級比 + 高,導(dǎo)致會先算 * 再算 + ,a等于5,乘以一還是5,再加上6就等于11。

那怎么讓他得到36呢,其實(shí)這里加個括號就可以了。

#include<stdio.h>
#define SQURE(x) (x) * (x)
int main()
{
	int a = 5;
	int b = SQURE(a + 1);
	printf("%d\n", b);
	return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
當(dāng)然,下面這種方法也是一樣的。
【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
我們只要確保替換之后運(yùn)算順序不發(fā)生改變就可以達(dá)到目的了。

下面是一個宏定義:

#define DOUBLE(x) (x) + (x)

定義中我們使用了括號,雖然這樣可以避免之前的問題,但是這個宏定義可能會出現(xiàn)新的問題:

#include<stdio.h>
#define DOUBLE(x) (x) + (x)
int main()
{
    int a = 5;
    printf("%d\n", 5 * DOUBLE(a));
    return 0;
}

按照慣性思維,我們可能會認(rèn)為打印50,但結(jié)果是否會是50呢?
【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
結(jié)果發(fā)現(xiàn)打印的是30,預(yù)處理之后生成目標(biāo)文件之后可以發(fā)現(xiàn)5會先和a相乘,然后再加a,導(dǎo)致結(jié)果與我們的出現(xiàn)誤差。
這個問題,的解決辦法是在宏定義表達(dá)式兩邊加上?對括號就可以了。

#define DOUBLE(x) ((x) + (x))

提示:所以用于對數(shù)值表達(dá)式進(jìn)行求值的宏定義都應(yīng)該用這種方式加上括號,避免在使用宏時由于參數(shù)中的操作符或鄰近操作符之間不可預(yù)料的相互作用。

四、帶有副作用的宏參數(shù)

當(dāng)宏參數(shù)在宏的定義中出現(xiàn)超過?次的時候,如果參數(shù)帶有副作用,那么你在使用這個宏的時候就可能出現(xiàn)危險,導(dǎo)致不可預(yù)測的后果。副作用就是表達(dá)式求值的時候出現(xiàn)的永久性效果。

【示例】

x+1;//不帶副作用
x++;//帶有副作用

【示例】:MAX宏可以證明具有副作用的參數(shù)所引起的問題。

#include<stdio.h>
#define MAX(x, y) ((x) > (y) ? (x) : (y))
int main()
{
    int a = 3;
    int b = 5;
    int m = MAX(a++, b++);
    printf("m = %d\n", m);
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
替換之后是一個三目運(yùn)算符,首先a = 3,b = 5,由于是后置加加,判斷之后才會加一,所以判斷之后a就等于4,b就等于6,因?yàn)楸磉_(dá)式為假,后面那個a++不會執(zhí)行,a還是等于4,后面的b++會執(zhí)行,但由于也是后置加加,先使用后再加一,即m就等于6,b就等于7。

結(jié)論:如果一個帶有副作用的參數(shù)在宏定義中出現(xiàn)兩份,就有可能出現(xiàn)不同的結(jié)果,即帶有副作用的參數(shù)是非常危險的,要盡量避免使用。

五、宏替換的規(guī)則

宏替換是C語言預(yù)處理器的一個重要功能,它在編譯之前進(jìn)行文本替換。宏替換遵循一定的規(guī)則,這些規(guī)則確保了宏能夠在正確的上下文中被替換為定義的文本,需要涉及幾個步驟:

  1. 文本替換
    宏定義中的所有文本都將被直接替換到宏名出現(xiàn)的任何位置。這意味著宏名在代碼中出現(xiàn)的每個地方,都會用宏定義中的文本替換。
#include<stdio.h>
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define M 10
int main()
{
    int a = 3;
    int b = 5;
    int m = MAX(a, M);
    printf("m = %d\n", m);
    printf("M = %d\n", M);
    printf("b = %d\n", b);
    return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言
每個宏名的位置都會用宏定義中的文本替換。

  1. 宏參數(shù)的保留
    當(dāng)宏名被替換時,宏參數(shù)將保持其原始的括號結(jié)構(gòu)。這是為了避免改變操作符的優(yōu)先級和結(jié)合性,確保代碼的邏輯不變。

  2. 宏參數(shù)的展開
    宏參數(shù)在替換時會展開,這意味著如果宏參數(shù)本身是一個宏,它也會被展開(替換)。這個過程稱為宏的展開或宏的宏展開。
    【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言

  3. 宏展開的順序
    當(dāng)宏參數(shù)中包含其他宏時,預(yù)處理器會按照它們在宏定義中出現(xiàn)的順序進(jìn)行替換。如果宏A中使用了宏B,而宏B又使用了宏C,那么預(yù)處理器首先會替換宏C,然后是宏B,最后是宏A。

  4. 宏展開的深度
    宏展開的深度是有限的。如果一個宏展開后仍然是一個宏(即宏的宏),這個過程會繼續(xù),但是有一個深度限制,以避免無限循環(huán)。

  5. 宏定義的順序
    宏定義的順序可能會影響宏替換的結(jié)果。如果兩個宏相互依賴,可能會導(dǎo)致預(yù)處理錯誤。為了解決這個問題,可以使用宏的函數(shù)樣宏形式,或者確保依賴關(guān)系正確。

  6. 宏定義的優(yōu)先級
    如果兩個宏定義具有相同的名稱,預(yù)處理器將使用最后一個定義。這意味著宏定義可以被后續(xù)的宏定義覆蓋。

  7. 條件編譯中的宏替換
    在使用#ifdef、#ifndef、#if、#else、#elif和#endif等條件編譯指令時,只有當(dāng)條件為真時,相關(guān)的宏才會被替換。

  8. 字符串化和標(biāo)記粘貼
    預(yù)處理器提供了特殊的宏操作符,如字符串化運(yùn)算符#和標(biāo)記粘貼運(yùn)算符##。字符串化運(yùn)算符可以將宏參數(shù)轉(zhuǎn)換為字符串字面量,而標(biāo)記粘貼運(yùn)算符可以將兩個宏參數(shù)連接成一個單一的標(biāo)識符。

  9. 宏展開的最佳實(shí)踐
    為了避免宏展開引起的問題,建議使用括號包圍宏參數(shù),避免宏定義過于復(fù)雜,以及避免宏名與關(guān)鍵字或現(xiàn)有標(biāo)識符沖突。

注意

  1. 宏參數(shù)和 #define 定義中可以出現(xiàn)其他 #define 定義的符號。但是對于宏,不能出現(xiàn)遞歸。
#include<stdio.h>
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define M 10
int main()
{
    int a = 3;
    int b = 5;
    int m = MAX(a, MAX(2, 3));
    printf("m = %d\n", m);
    printf("M = %d\n", M);
    printf("b = %d\n", b);
    return 0;
}

【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-855329.html

  1. 當(dāng)預(yù)處理器搜索 #define 定義的符號的時候,字符串常量的內(nèi)容并不被搜索。
    【C語言基礎(chǔ)】:預(yù)處理詳解(一),C/C++基礎(chǔ),c語言,開發(fā)語言

到了這里,關(guān)于【C語言基礎(chǔ)】:預(yù)處理詳解(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C語言】預(yù)處理詳解

    【C語言】預(yù)處理詳解

    ???????? 本文目錄 1 預(yù)定義符號 2 #define 2.1 #define 定義標(biāo)識符 2.2 #define 定義宏 2.3 #define 替換規(guī)則 2.4 #和## 2.5 帶副作用的宏參數(shù) 2.6 宏和函數(shù)對比 2.7 命名約定 3 #undef 4 命令行定義 5 條件編譯 6 文件包含 6.1 頭文件被包含的方式 6.2 嵌套文件包含 這些預(yù)定義符號都是語言內(nèi)置

    2024年02月14日
    瀏覽(36)
  • C語言·預(yù)處理詳解

    C語言·預(yù)處理詳解

    ????????C語言設(shè)置了一些預(yù)定義符號,可以直接使用,預(yù)定義符號也是在預(yù)處理期間處理的 ????????????????__FILE__ ?進(jìn)行編譯的源文件 ????????????????__LINE__ ?文件當(dāng)前的行號 ????????????????__DATE__ ?文件被編譯的日期 ????????????????_

    2024年01月21日
    瀏覽(34)
  • 【C語言進(jìn)階】預(yù)處理詳解

    【C語言進(jìn)階】預(yù)處理詳解

    對預(yù)處理的相關(guān)知識進(jìn)行詳細(xì)的介紹 ? ? ? ? ? ? ? ? ??? 豬巴戒 :個人主頁? ??????????????? 所屬專欄 :《C語言進(jìn)階》 ? ? ? ? ?? 跟著豬巴戒 ,一起學(xué)習(xí)C語言?? 目錄 引言 預(yù)定義符號 #define定義常量 #define定義宏 帶有副作用的宏參數(shù) 宏替換的規(guī)則 宏函數(shù)的

    2024年01月23日
    瀏覽(26)
  • 【C語言:編譯、預(yù)處理詳解】

    【C語言:編譯、預(yù)處理詳解】

    我們都知道,一個程序如果想運(yùn)行起來要經(jīng)過編譯、鏈接然后才能生成.exe的文件。 編譯?可以分解為三個過程: 預(yù)處理(有些書也叫預(yù)編譯)、 編譯 匯編 預(yù)處理階段 主要處理那些源文件中以#開始的預(yù)編譯指令。比如:#include,#define,處理的規(guī)則如下: 刪除所有的注釋

    2024年02月03日
    瀏覽(24)
  • 【c語言】詳解c語言#預(yù)處理期過程 | 宏定義前言

    【c語言】詳解c語言#預(yù)處理期過程 | 宏定義前言

    c語言系列專欄:?c語言之路重點(diǎn)知識整合?? 創(chuàng)作不易,本篇文章如果幫助到了你,還請點(diǎn)贊支持一下???)!!? 主頁專欄有更多知識,如有疑問歡迎大家指正討論,共同進(jìn)步! 給大家跳段街舞感謝支持!? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 代碼編譯到執(zhí)

    2024年02月01日
    瀏覽(28)
  • 初始C語言最后一章《編譯、鏈接與預(yù)處理詳解》

    初始C語言最后一章《編譯、鏈接與預(yù)處理詳解》

    感謝老鐵們的陪伴和支持,初始C語言專欄在本章內(nèi)容也是要結(jié)束了,這創(chuàng)作一路下來也是很不容易,如果大家對 Java 后端開發(fā)感興趣,歡迎各位老鐵來我的Java專欄!當(dāng)然了,我也會更新幾章C語言實(shí)現(xiàn)簡單的數(shù)據(jù)結(jié)構(gòu)!不過由于我是Java 技術(shù)棧的,所以如果以后有機(jī)會學(xué)習(xí)C

    2024年04月16日
    瀏覽(23)
  • 【C語言】預(yù)處理詳解:#define的各種使用方法

    【C語言】預(yù)處理詳解:#define的各種使用方法

    目錄 1.#define定義標(biāo)識符 1.1賦值 1.2? ?定義 1.3用更形象的符號來替換一種實(shí)現(xiàn) 1.4? ?加續(xù)行符換行 1.5#define定義宏 1.6? #define替換的規(guī)則 注意事項(xiàng) 2.#和## 3.帶有副作用的宏參數(shù) 4.函數(shù)和宏的對比 #define定義標(biāo)識符的用法非常簡單 name可以由自己來命名,盡量取一些有意義

    2024年02月15日
    瀏覽(32)
  • C語言中程序的編譯(預(yù)處理操作)+鏈接詳解(詳細(xì)介紹程序預(yù)編譯過程)

    C語言中程序的編譯(預(yù)處理操作)+鏈接詳解(詳細(xì)介紹程序預(yù)編譯過程)

    今天我們來學(xué)習(xí)C語言中程序的編譯和鏈接是如何進(jìn)行的。 在ANSI C的任何一種實(shí)現(xiàn)中,存在兩個不同的環(huán)境。 第1種是翻譯環(huán)境,在這個環(huán)境中源代碼被轉(zhuǎn)換為可執(zhí)行的機(jī)器指令。 第2種是執(zhí)行環(huán)境,它用于實(shí)際執(zhí)行代碼。 本文主要是介紹預(yù)編譯階段的相關(guān)知識。 1.組成一個程

    2023年04月09日
    瀏覽(34)
  • C語言之預(yù)處理命令使用詳解----#if、#endif、#undef、#ifdef、#else、#elif

    查了好久才知道的這個原理,記錄一下吧! 參考教程 預(yù)處理命令 在接觸#if、#undef這類預(yù)處理指令前,大部分都都接觸過#define、#include等預(yù)處理命令,通俗來講預(yù)處理命令的作用就是在編譯和鏈接之前,對源文件進(jìn)行一些文本方面的操作,比如文本替換、文件包含、刪除部分

    2024年02月02日
    瀏覽(23)
  • C語言——程序環(huán)境和預(yù)處理(再也不用擔(dān)心會忘記預(yù)處理的知識)

    C語言——程序環(huán)境和預(yù)處理(再也不用擔(dān)心會忘記預(yù)處理的知識)

    先簡單了解一下程序環(huán)境,然后詳細(xì)總結(jié)翻譯環(huán)境里的編譯和鏈接,然后在總結(jié)編譯預(yù)處理。 在 ANSI C 的任何一種實(shí)現(xiàn)中,存在兩個不同的環(huán)境 翻譯環(huán)境:這個環(huán)境中源代碼被轉(zhuǎn)換為可執(zhí)行的機(jī)器指令。 執(zhí)行環(huán)境:執(zhí)行二進(jìn)制代碼。 計(jì)算機(jī)如何執(zhí)行二進(jìn)制指令? 我們寫的C語

    2024年02月09日
    瀏覽(36)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包