<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
宏定義數值常數相信大家都不陌生,相信很多小夥伴用過,這裡我們就簡單的提一下,我們前面也講過,#define 本質上是替換,它可以出現在程式碼的任何地方,也可以把任何東西都定義成宏,編譯器會在預編譯的時候進行替換掉,舉例:
#dfeine PI 3.1415926
這樣在以後的程式碼中你就可以用 PI 來代替 3.1415926 那麼這樣做的好處是什麼呢?假設在未來的某一天,你要提升這個精度,如果你程式碼中出現 3.1415926 過多的話,你提升精度還得一個個修改, 如果使用宏定義的話,你只需要改一次即可。
除了宏定義常數之外,還經常用來定義字串,特別是路徑:
① #define PATH_1 D:codelesson1test
②#define PATH_1 "D:codelesson1test"
以上哪個是正確的呢?如果覺得太長還可以用續行符:
③ #define PATH_1 "D:codelesson1\test"
很顯然第一個肯定是不對的,字串需要用 "" 引起來,第三個也不對,第二個呢?我們去實踐證明下(以上寫法都不推薦!):
在Linux平臺環境下:
在Windows環境下:
很顯然他們都有同樣的警告,都是未知跳脫序列,也無法正確列印出我們的路徑,在前面我們講到,' ' 是跳脫字元,當我們要列印路徑的時候需要用跳脫字元 ' ' 去還原 ' ' 的字面意思,所以這裡列印路徑要用 \ !
注意:Windows路徑分隔是用 ' ',而Linux路徑分隔是用 ' / ',所以如上測試用例改成 ' / ' 的話是不會報警告的。
所以要正確的列印如上用例應該這樣寫:
//不使用續行符 #define PATH_1 "D:\code\lesson1\test" //使用續行符 #define PATH_1 "D:\code\lesson1\test"
因為 Linux 環境能直接檢視預處理過程,便於我們驗證,所以我們下邊會在 Linux 環境下測試。
我們先簡單瞭解下程式的翻譯過程:
這裡我們來看一段用宏充當註釋符號的程式碼:
#include <stdio.h> #define BSC // int main() { BSC printf("hello worldn"); printf("you can see me!n"); return 0; }
這裡我們要探討一個什麼問題呢?如果替換成功,則不會執行第一個函數,如果替換失敗,則我們會看到兩行列印:
這究竟是為什麼呢?我們可以執行:
[lwp@localhost code]$ gcc -E test.c -o test.i
把預處理後的結果保留下來為 test.i 檔案,接著我們可以去用 vim 編輯器檢視一下它與原始檔的區別在哪,究竟是如何替換的:
通過上圖我們可以發現,在預處理之後的檔案中,並沒有去成功通過宏替換註釋掉第一個 printf 函數,由此可見,在預處理階段,是先執行去掉註釋,然後在進行宏替換,如上程式碼,本質是直接定義了一個空宏,我們特別不推薦這樣寫程式碼!(C語言註釋風格也一樣不行,感興趣可以下去嘗試下)
先看一段程式碼:
#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, %dn", a, b); return 0; }
我想請問,這段程式碼有問題嗎?應該如何改進呢?這段程式碼明顯是編譯不會通過的,但是可以通過執行預處理指令,發現預處理並沒有出問題,那麼,我們可以看一下預處理之後的結果與原始檔的區別在哪:
通過預處理之後的結果我們可以看到,宏替換多了一個分號。於是有小夥伴就討論出來如下三種解決方法:
第一種解決方法肯定是不行的,去掉最後一個分號並不能解決問題,if else 在沒有大括號的情況下後面只能跟一條語句,所以第一條行不通。
第二種解決方案看似不錯,但是我們有沒有想過,並不是所有人都會有良好的程式碼風格,我們作為程式設計師,寫出的宏應該具有健壯性,所以第二條不可取。
第三種解決方案我們看著好像靠譜,但是我們通常寫完一條語句中後面都會帶上分號,那可想而知會出現這種情況:{a = 0, b = 0;}; 大括號外是不能跟分號的,所以這個方法也不可取!
最好的解決方法是什麼呢?使用 do while 結構:
#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, %dn", 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, %dn", a, b); return 0; }
迴圈會被看成一條複合語句,所以 if 不帶大括號也沒事(建議帶上),這樣我們的宏就會更健壯,也不會出錯,同時你也可以在中間新增續行符,讓他們的格式更清晰!同時我也有個小建議,宏定義的結尾最好都不要帶分號。
結論: 當我們需要宏進行多條語句替換的時候,推薦使用 do-while-zero結構。
【建議1】在宏定義體的結尾省略分號。
【建議2】函數宏的呼叫不能省略引數。
【建議3】函數宏的定義中,每個引數都應該以小括號括起來,避免替換之後出現優先順序的問題。
第一個問題,宏定義的位置有限制要求嗎?
答案:原始檔的任何地方,宏都可以定義,與是否在函數內外無關。
第二個問題,宏的有效範圍有多大呢?
#include <stdio.h> void test() { printf("test: %dn", M); } int main() { test(); #define M 10 printf("main: %dn", M); return 0; }
這段程式碼我們就發現編譯不通過了,那麼我們來進入預處理檔案來對比下原始檔:
答案:宏的作用範圍,從定義處開始,往後都是有效的!
這裡我們用一個例子就能很好的證明了:
#include <stdio.h> #define M 10 int main() { printf("%dn", M); #undef M printf("undef: %dn", M); return 0; }
我們來檢視如上程式碼的預處理之後的結果:
結論:undef 是取消宏的意思,可以用來限定宏的有效範圍!
#include <stdio.h> int main() { #define X 3 #define Y X*2 #undef X #define X 2 int z = Y; printf("%dn", z); return 0; }
請問小夥伴們,這段程式碼列印什麼?
這裡我就不截圖給大家看了,感興趣的可以自行下去敲一敲,經過Linux平臺和windows平臺的測試,最終列印的都是 4,因為編譯器都是從上到下掃描程式碼的,以最近的宏定義為準。
到此這篇關於C語言零基礎徹底掌握預處理上篇的文章就介紹到這了,更多相關C語言預處理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45