欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言零基礎(chǔ)徹底掌握預(yù)處理上篇

 更新時(shí)間:2022年08月09日 10:52:59   作者:程序猿教你打籃球  
在C語(yǔ)言的程序中包括各種以符號(hào)#開(kāi)頭的編譯指令,這些指令稱(chēng)為預(yù)處理命令。預(yù)處理命令屬于C語(yǔ)言編譯器,而不是C語(yǔ)言的組成部分,通過(guò)預(yù)處理命令可擴(kuò)展C語(yǔ)言程序設(shè)計(jì)的環(huán)境

1、#define的深度認(rèn)識(shí)

1.1 數(shù)值宏常量

宏定義數(shù)值常量相信大家都不陌生,相信很多小伙伴用過(guò),這里我們就簡(jiǎn)單的提一下,我們前面也講過(guò),#define 本質(zhì)上是替換,它可以出現(xiàn)在代碼的任何地方,也可以把任何東西都定義成宏,編譯器會(huì)在預(yù)編譯的時(shí)候進(jìn)行替換掉,舉例:

#dfeine PI 3.1415926

這樣在以后的代碼中你就可以用 PI 來(lái)代替 3.1415926 那么這樣做的好處是什么呢?假設(shè)在未來(lái)的某一天,你要提升這個(gè)精度,如果你代碼中出現(xiàn) 3.1415926 過(guò)多的話,你提升精度還得一個(gè)個(gè)修改, 如果使用宏定義的話,你只需要改一次即可。

1.2 字符串宏常量

除了宏定義常量之外,還經(jīng)常用來(lái)定義字符串,特別是路徑:

① #define PATH_1 D:\code\lesson1\test

②#define PATH_1 "D:\code\lesson1\test"

以上哪個(gè)是正確的呢?如果覺(jué)得太長(zhǎng)還可以用續(xù)行符:

③ #define PATH_1 "D:\code\lesson1\\test"

很顯然第一個(gè)肯定是不對(duì)的,字符串需要用 "" 引起來(lái),第三個(gè)也不對(duì),第二個(gè)呢?我們?nèi)?shí)踐證明下(以上寫(xiě)法都不推薦?。?/p>

在Linux平臺(tái)環(huán)境下:

在Windows環(huán)境下:

很顯然他們都有同樣的警告,都是未知轉(zhuǎn)義序列,也無(wú)法正確打印出我們的路徑,在前面我們講到,' \ ' 是轉(zhuǎn)義字符,當(dāng)我們要打印路徑的時(shí)候需要用轉(zhuǎn)義字符 ' \ ' 去還原 ' \ ' 的字面意思,所以這里打印路徑要用 \\ !

注意:Windows路徑分隔是用 ' \ ',而Linux路徑分隔是用 ' / ',所以如上測(cè)試用例改成 ' / ' 的話是不會(huì)報(bào)警告的。

所以要正確的打印如上用例應(yīng)該這樣寫(xiě):

//不使用續(xù)行符
#define PATH_1 "D:\\code\\lesson1\\test"
//使用續(xù)行符
#define PATH_1 "D:\\code\\lesson1\\\test"

1.3 用宏充當(dāng)注釋符號(hào)

因?yàn)?Linux 環(huán)境能直接查看預(yù)處理過(guò)程,便于我們驗(yàn)證,所以我們下邊會(huì)在 Linux 環(huán)境下測(cè)試。

我們先簡(jiǎn)單了解下程序的翻譯過(guò)程:

  1. 預(yù)處理-E:頭文件展開(kāi),去注釋?zhuān)晏鎿Q,條件編譯...
  2. 編譯-S:將預(yù)處理后的C語(yǔ)言翻譯成匯編語(yǔ)言
  3. 匯編-c:將匯編語(yǔ)言轉(zhuǎn)化為可目標(biāo)二進(jìn)制文件( 可被鏈接 )
  4. 鏈接:將目標(biāo)二進(jìn)制文件與相關(guān)庫(kù)鏈接,形成可執(zhí)行程序

這里我們來(lái)看一段用宏充當(dāng)注釋符號(hào)的代碼:

#include <stdio.h>
#define BSC //
int main()
{
	BSC printf("hello world\n");
	printf("you can see me!\n");
	return 0;
}

這里我們要探討一個(gè)什么問(wèn)題呢?如果替換成功,則不會(huì)執(zhí)行第一個(gè)函數(shù),如果替換失敗,則我們會(huì)看到兩行打?。?/p>

這究竟是為什么呢?我們可以執(zhí)行:

[lwp@localhost code]$ gcc -E test.c -o test.i

把預(yù)處理后的結(jié)果保留下來(lái)為 test.i 文件,接著我們可以去用 vim 編輯器查看一下它與源文件的區(qū)別在哪,究竟是如何替換的:

通過(guò)上圖我們可以發(fā)現(xiàn),在預(yù)處理之后的文件中,并沒(méi)有去成功通過(guò)宏替換注釋掉第一個(gè) printf 函數(shù),由此可見(jiàn),在預(yù)處理階段,是先執(zhí)行去掉注釋?zhuān)缓笤谶M(jìn)行宏替換,如上代碼,本質(zhì)是直接定義了一個(gè)空宏,我們特別不推薦這樣寫(xiě)代碼!(C語(yǔ)言注釋風(fēng)格也一樣不行,感興趣可以下去嘗試下)

1.4 用宏替換多條語(yǔ)句

先看一段代碼:

#include <stdio.h>
#define INIT_VALUE(a, b) a = 0; b = 0;
int main()
{
    int flag = 0;
    scanf("%d", &flag);
    int a = 100;
    int b = 200;
    if (flag)
        INIT_VALUE(a, b);
    else
        printf("%d, %d\n", a, b);
     return 0;
}

我想請(qǐng)問(wèn),這段代碼有問(wèn)題嗎?應(yīng)該如何改進(jìn)呢?這段代碼明顯是編譯不會(huì)通過(guò)的,但是可以通過(guò)執(zhí)行預(yù)處理指令,發(fā)現(xiàn)預(yù)處理并沒(méi)有出問(wèn)題,那么,我們可以看一下預(yù)處理之后的結(jié)果與源文件的區(qū)別在哪:

通過(guò)預(yù)處理之后的結(jié)果我們可以看到,宏替換多了一個(gè)分號(hào)。于是有小伙伴就討論出來(lái)如下三種解決方法:

  • 去掉宏定義的最后一個(gè)分號(hào)
  • 規(guī)范代碼風(fēng)格,給 if 和 else 加上大括號(hào)
  • 給宏定義要替換的部分用大括號(hào)括起來(lái)

第一種解決方法肯定是不行的,去掉最后一個(gè)分號(hào)并不能解決問(wèn)題,if else 在沒(méi)有大括號(hào)的情況下后面只能跟一條語(yǔ)句,所以第一條行不通。

第二種解決方案看似不錯(cuò),但是我們有沒(méi)有想過(guò),并不是所有人都會(huì)有良好的代碼風(fēng)格,我們作為程序員,寫(xiě)出的宏應(yīng)該具有健壯性,所以第二條不可取。

第三種解決方案我們看著好像靠譜,但是我們通常寫(xiě)完一條語(yǔ)句中后面都會(huì)帶上分號(hào),那可想而知會(huì)出現(xiàn)這種情況:{a = 0, b = 0;}; 大括號(hào)外是不能跟分號(hào)的,所以這個(gè)方法也不可取!

最好的解決方法是什么呢?使用 do while 結(jié)構(gòu):

#include <stdio.h>#define INIT_VALUE(a, b) do{a = 0; b = 0;}while(0)int main(){ int flag = 0; scanf("%d", &flag); int a = 100; int b = 200; if (flag) INIT_VALUE(a, b); else printf("%d, %d\n", a, b); return 0;}#include <stdio.h>
#define INIT_VALUE(a, b) do{a = 0; b = 0;}while(0)
int main()
{
    int flag = 0;
    scanf("%d", &flag);
    int a = 100;
    int b = 200;
    if (flag)
        INIT_VALUE(a, b);
    else
        printf("%d, %d\n", a, b);
     return 0;
}

循環(huán)會(huì)被看成一條復(fù)合語(yǔ)句,所以 if 不帶大括號(hào)也沒(méi)事(建議帶上),這樣我們的宏就會(huì)更健壯,也不會(huì)出錯(cuò),同時(shí)你也可以在中間添加續(xù)行符,讓他們的格式更清晰!同時(shí)我也有個(gè)小建議,宏定義的結(jié)尾最好都不要帶分號(hào)。

結(jié)論: 當(dāng)我們需要宏進(jìn)行多條語(yǔ)句替換的時(shí)候,推薦使用 do-while-zero結(jié)構(gòu)。

1.5 宏定義的使用建議

【建議1】在宏定義體的結(jié)尾省略分號(hào)。

【建議2】函數(shù)宏的調(diào)用不能省略參數(shù)。

【建議3】函數(shù)宏的定義中,每個(gè)參數(shù)都應(yīng)該以小括號(hào)括起來(lái),避免替換之后出現(xiàn)優(yōu)先級(jí)的問(wèn)題。

2、#undef 撤銷(xiāo)宏

2.1 宏的定義位置和有效范圍

第一個(gè)問(wèn)題,宏定義的位置有限制要求嗎?

答案:源文件的任何地方,宏都可以定義,與是否在函數(shù)內(nèi)外無(wú)關(guān)。

第二個(gè)問(wèn)題,宏的有效范圍有多大呢?

#include <stdio.h>                                                                                                                     
void test()
{
     printf("test: %d\n", M);
 }
int main()
{
     test();
 #define M 10
     printf("main: %d\n", M);
     return 0;
 }

這段代碼我們就發(fā)現(xiàn)編譯不通過(guò)了,那么我們來(lái)進(jìn)入預(yù)處理文件來(lái)對(duì)比下源文件:

答案:宏的作用范圍,從定義處開(kāi)始,往后都是有效的!

2.2 宏的取消

這里我們用一個(gè)例子就能很好的證明了:

 #include <stdio.h>                                                                                                                     
  
  #define M 10
  int main()
  {
       printf("%d\n", M);
  #undef M
       printf("undef: %d\n", M);
       return 0;
  } 

我們來(lái)查看如上代碼的預(yù)處理之后的結(jié)果:

結(jié)論:undef 是取消宏的意思,可以用來(lái)限定宏的有效范圍!

2.3 一道筆試題

#include <stdio.h>
int main()
{
#define X 3
#define Y X*2
#undef X
#define X 2
	int z = Y;
	printf("%d\n", z);
	return 0;
}

請(qǐng)問(wèn)小伙伴們,這段代碼打印什么?

這里我就不截圖給大家看了,感興趣的可以自行下去敲一敲,經(jīng)過(guò)Linux平臺(tái)和windows平臺(tái)的測(cè)試,最終打印的都是 4,因?yàn)榫幾g器都是從上到下掃描代碼的,以最近的宏定義為準(zhǔn)。

到此這篇關(guān)于C語(yǔ)言零基礎(chǔ)徹底掌握預(yù)處理上篇的文章就介紹到這了,更多相關(guān)C語(yǔ)言預(yù)處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解C++17中nodiscard標(biāo)記符的使用

    詳解C++17中nodiscard標(biāo)記符的使用

    在C++?17中引入了一個(gè)標(biāo)記符nodiscard,用于聲明一個(gè)?“非棄值(no-discard)表達(dá)式”。這篇文章就來(lái)和大家來(lái)聊一聊nodiscard標(biāo)記符的使用吧
    2023-02-02
  • Clion下載安裝使用的詳細(xì)教程(Win+MinGW)

    Clion下載安裝使用的詳細(xì)教程(Win+MinGW)

    這篇文章主要介紹了Clion下載安裝使用教程(Win+MinGW),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • C++設(shè)計(jì)模式之簡(jiǎn)單工廠模式實(shí)例

    C++設(shè)計(jì)模式之簡(jiǎn)單工廠模式實(shí)例

    這篇文章主要介紹了C++設(shè)計(jì)模式之簡(jiǎn)單工廠模式實(shí)例,工廠模式有一種非常形象的描述,建立對(duì)象的類(lèi)就如一個(gè)工廠,而需要被建立的對(duì)象就是一個(gè)個(gè)產(chǎn)品,需要的朋友可以參考下
    2014-09-09
  • C語(yǔ)言找出數(shù)組中的特定元素的算法解析

    C語(yǔ)言找出數(shù)組中的特定元素的算法解析

    這篇文章主要介紹了C語(yǔ)言中找出數(shù)組中特定元素的算法解析,包括找出數(shù)組中兩個(gè)只出現(xiàn)一次的數(shù)字的方法,需要的朋友可以參考下
    2016-03-03
  • C++ Boost Tokenizer使用詳細(xì)講解

    C++ Boost Tokenizer使用詳細(xì)講解

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)
    2022-11-11
  • C語(yǔ)言模式實(shí)現(xiàn)C++繼承和多態(tài)的實(shí)例代碼

    C語(yǔ)言模式實(shí)現(xiàn)C++繼承和多態(tài)的實(shí)例代碼

    本篇文章主要介紹了C語(yǔ)言模式實(shí)現(xiàn)C++繼承和多態(tài)的實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • C++進(jìn)程的創(chuàng)建和進(jìn)程ID標(biāo)識(shí)詳細(xì)介紹

    C++進(jìn)程的創(chuàng)建和進(jìn)程ID標(biāo)識(shí)詳細(xì)介紹

    傳統(tǒng)的C++(C++98)中并沒(méi)有引入線程這個(gè)概念。linux和unix操作系統(tǒng)的設(shè)計(jì)采用的是多進(jìn)程,進(jìn)程間的通信十分方便,同時(shí)進(jìn)程之間互相有著獨(dú)立的空間,不會(huì)污染其他進(jìn)程的數(shù)據(jù),天然的隔離性給程序的穩(wěn)定性帶來(lái)了很大的保障
    2022-08-08
  • C語(yǔ)言實(shí)現(xiàn)手寫(xiě)Map(數(shù)組+鏈表+紅黑樹(shù))的示例代碼

    C語(yǔ)言實(shí)現(xiàn)手寫(xiě)Map(數(shù)組+鏈表+紅黑樹(shù))的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)手寫(xiě)Map(數(shù)組+鏈表+紅黑樹(shù)),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定借鑒價(jià)值,需要的可以參考一下
    2022-09-09
  • 從匯編看c++中變量類(lèi)型的深入分析

    從匯編看c++中變量類(lèi)型的深入分析

    本篇文章是對(duì)c++中的變量類(lèi)型進(jìn)行了詳細(xì)的分析介紹。需要的朋友參考下
    2013-05-05
  • C++中的動(dòng)態(tài)規(guī)劃子序列問(wèn)題分析探討

    C++中的動(dòng)態(tài)規(guī)劃子序列問(wèn)題分析探討

    可能有些讀者有接觸過(guò)動(dòng)態(tài)規(guī)劃,可能也有一些讀者以前完全不知道動(dòng)態(tài)規(guī)劃這個(gè)東西,別擔(dān)心,我這篇文章會(huì)為讀者做一個(gè)入門(mén),好讓讀者掌握這個(gè)重要的知識(shí)點(diǎn)
    2023-03-03

最新評(píng)論