“#if 0/#if 1 ... #endif”的真實作用

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。    https://blog.csdn.net/L_Andy/article/details/45100323
1、先說“#if 0/#if 1 ... #endif”的作用,樓上諸位或多或少都說到了一點,但都沒有說到關鍵的地方。我們知道,C標準不提供C++裏的“//”這樣的單行風格註釋而只提供“/* */”這樣的塊註釋功能,我們通常使用它寫代碼中說明性的註釋文字(註釋作用)以及在調試時關閉某段代碼對編譯器的可見性(屏蔽作用),當然,這裏所謂的“註釋作用”和“屏蔽作用”是我們從功能上下的主觀定義,對預處理器而言,兩者並無任何區別。對於前者,因爲“註釋”中不會再出現“註釋”和“需要屏蔽的代碼段”,所以不會有嵌套的需求,所以通常不會有問題;而對於後者,當我們在調試程序時需要“屏蔽”某段代碼時,該段代碼中可能包含着前述的“註釋”和/或“已被屏蔽的代碼段”,這時就產生了“/* */”嵌套使用的需求,但SB的C標準恰恰不允許我們這麼幹。當你試圖使用嵌套的塊註釋功能時,會發現預處理器把最外層註釋的開始和最內層註釋的結尾這兩者之間的內容處理成了註釋,而其後一直到最外層註釋結尾的內容被當作了“有效代碼”——這顯然會引起若干語法錯誤而導致編譯中止。高手們開動腦筋想到了“#if 0 ... #endif”,它同樣由預處理器進行處理,同樣可以“屏蔽”一段代碼,你想把說明文字寫在裏面也可以,這些和“/* */”都一樣,但不一樣的是:第一它允許嵌套(層數上限由預處理器決定)、第二你隨時可以把“#if 0”改成“#if 1”來取消對某段代碼的“屏蔽”——很卓越的特性,快拋棄笨拙的“/* */”吧!它唯一的缺點就是在編輯器中沒有“註釋”該有的文本顯示樣式。

2、現在再來說說2樓提到的自動變量局部化的問題:
------------------------------------------------
通過google,得知:

#if 0
   code
#endif 


(1)code中定義的是一些調試版本的代碼,此時code完全被編譯器忽略。如果想讓code生效,只需把#if 0改成#if 1 
(2)#if 0還有一個重要的用途就是用來當成註釋,如果你想要註釋的程序很長,這個時候#if 0是最好的,保證不會犯錯誤。(但是林銳的書上說千萬不要把#if 0 來當作塊註釋使用) 
#if 1可以讓其間的變量成爲局部變量。 
(3)這個結構表示你先前寫好的code,現在用不上了,又不想刪除,就用這個方法,比註釋方便。 
------------------------------------------------

通過我上面說的第一點,我們可以知道,對“#if/#endif”的處理是預處理器完成的,而預處理器的唯一工作就是作“文字替換”的“預處理”工作,它並不負責常數符號表的生成、變量存儲空間的分配、代碼的重定位等工作,那麼完全是給預處理器看的“#if/#endif”怎麼能控制變量的生存期、怎麼能決定變量可以在哪裏定義??
打開編輯器,寫下如下代碼:


===========================
volatile unsigned char a;
unsigned int main(void)
{
        a = 0;
#if     1
        unsigned char *p = &a;
        *p = 255;
#endif
        return 0;
}
===========================


存成.c文件後用任何C編譯器(不包括C++編譯器)編譯,都會在紅字那一行報錯——爲什麼呢?因爲預處理器進行“預處理”的時候發現if的條件表達式爲“真”,所以它把那段代碼塊留下了,而只把代碼塊前後的“預處理指示符號(或者叫做預處理命令)”給清除掉了,這樣,預處理後的結果交給編譯器“翻譯”的時候,它發現在一個函數(在這裏爲main函數)內部的表達式語句(在這裏是a = 0;)之後發現了變量聲明/定義語句(在這裏是聲明並定義指針變量p的語句)——按照編譯器的規則,這是一個錯誤,所以它拒絕接受這樣的輸入、罷工並開始抱怨(中止編譯、給出錯誤信息)。

至此,關於“#if 1/#if 0/#endif”,我要說的就全說完了,歡迎大家拍磚哈~_~


下面再多囉嗦兩句。
--------------------------
那麼我們能不能享受C++程序員所得到的“將變量的定義放在它開始被需要的地方”這種待遇呢?
答案是肯定的。
手段?
——代碼塊!

  用一對大括號括起來的代碼塊的首部,可以聲明/定義變量,這些變量的作用域僅限於該代碼塊內部,當然,這些變量聲明/定義語句也必須全部位於該代碼塊中第一個表達式語句之前,不然會出現上面描述的錯誤,不過好在C編譯器允許我們在代碼塊中嵌套定義代碼塊,所以大家從現在開始,大可不必在函數的開頭定義一大堆變量,那裏只要寫一些在整個函數執行過程當中都需要的變量的聲明/定義語句就好了;至於循環結構的循環變量等這些生存期不長的變量,它們的聲明/定義語句完全可以放在一個用一對大括號括起來的代碼塊的首部。
  囉嗦了這麼多,寫一小段代碼證明一下我的說法,呵呵:


===========================
volatile unsigned char a;
unsigned int main(void)
{
        a = 0;
        {       //注
        unsigned char *p = &a;
        *p = 255;
        }
        return 0;
}
===========================


  注:我個人的代碼書寫風格是大括號獨佔一行並且縮進量與父語句相同,函數體、循環體、case、if四者中的語句增加縮進,但如上的“代碼塊”則不增加。
存盤、編譯。
Hmmmm,編譯器不再在紅色的行給出錯誤提示了,編譯通過,得證~_~
--------------------- 
作者:卡哥 
來源:CSDN 
原文:https://blog.csdn.net/l_andy/article/details/45100323 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章