因為一直好奇預處理器的工作機制,所以就查了查書,做一下這方面的筆記。
雖然頂著預處理器的名頭,但預處理器卻並不是第乙個就拿到源**的。因為在對程式進行預處理之前,編譯器會對源**進行幾次翻譯工作,諸如:將字元對映到源字符集上、將注釋換成空格等等的處理,這才是真正的第一步預處理。而為什麼這些東西要交給編譯器來處理呢,這是因為「預處理器不能理解c,它一般是接受一些文字並將其轉換為其他文字」,這句話就是說:c預處理器它並不明白c語言的**規範,它會的只是將一些文字轉換為另一些文字。仔細想想c預處理器的功能是不是和記事本中的「替換」功能很像哈哈。
當編譯器按照c語言的**規範將源**進行處理之後,接下來就輪到了我們的預處理器登場了。預處理器會尋找可能是預處理指令的文字,而尋找這些指令的重要依據就是「#」符號,講到這就要說一說預處理的主要任務了。
1、轉換處理(替換)。#define指令最為典型的問題就是:符號的優先順序問題,如下所示:做這方面的預處理指令有很多,如我們常用的#include和#define預編譯指令,他們基本的工作方式還是有些相同的,#include指令是將標頭檔案中的源**注入到該指令所處的位置;而#define則是定義了將一些字元a對映到另一些字元b上(命令約定),從而使得只要改動a就可以讓預處理器去修改b的值,這種牽一髮而動身的做法可以使得我們節約很多時間。但是要注意的是,他們都僅僅是將一些文字替換成了另一些文字,因此這種轉換處理用的好是事半功倍,用的不好也會使得自己崩潰啊。
2、條件編譯(有選擇性的包含源**)。
聽起來這個名字好像是編譯器要幹的事,但是這卻實實在在是預處理器要完成的工作。雖然之前說預處理器不理解c的**規範,但是這並不會影響到他自己擁有自己的規範啊,諸多的預編譯指令就是預編譯器的語言規範。而為條件編譯準備的預處理指令也有很多,諸如#ifndef、#elif和#endif等等。所有的也這些都是讓我們有選擇性的將我們編寫的**來交給編譯器,進而讓編譯器來編譯我們的**。
當然了,預處理器的作用還有很多,上述的作用也只是在我看來比較重要的,如果有錯誤還望批評指正。
這又一次說明了,c預處理器它並不懂的c語言的**規範,它有的只是簡單的文字「替換」功能。
解決方法:
在巨集定義中使用「()」來保證優先順序的正確性。可是即使這樣還是會出現優先順序的問題,如下所示:
當然了,這個問題還是可以通過加「()」解決,如下:
#define f(x) ((x)*(x))
但是這的確給我們增大了使用巨集定義的難度,我們要頻繁的使用「()」來保證優先順序的正確性,但是這並不代表其就沒有優點:
1、可以很容易的將所有常量的定義集中在一起,這方便我們對這些變數的修改。
2、在c語言中,大多數在呼叫函式時都會帶來重大的系統開銷,而利用#define指令的文字「替換」功能,就可以使程式塊看上去像乙個函式,但是卻沒有函式呼叫的開銷。
而使用巨集而造成的問題的確會給我們帶來困擾,所以才有了之後的內聯函式的出現。
我們通過一些小的測試來更好的理解檔案包含指令,如下所示:
實驗1:
main.cpp
#include
#include
"myhead.h"
intmain()
myhead.h
int number;
修改一下main.cpp檔案:
#include
#include
"myhead.h"
int number;
intmain()
執行結果:
從上面的小實驗中,我們很容易看出myhead.**件中的**的確被注入到#include指令所在的位置了,因此當我又定義乙個變數number時才會出現重複定義這個錯誤。
實驗2:
main.cpp
#include
#include
"myhead.h"
#include
"testone.h"
intmain()
myhead.h
#include
"testone.h"
testone.h
int number=
100;
執行結果:
這個錯誤再次印證了預處理器只是將文字進行了簡單的「替換」而已,main.cpp檔案重複的包含了檔案testone.h中的內容,才導致了number變數的重定義。而解決方法就是條件編譯,這也是我以前會經常犯的錯誤。
testone.h
#ifndef _testone_
//如果沒有定義_testone_變數,執行下面**,如果定義過了,就不執行下面**
#define _testone_
int number=
100;
#endif
這樣就保證了testone.h中的**只會被編譯器編譯一次,從而保證了**不會因為重複包含檔案而出現錯誤。這也解釋了下面了這種情況為啥不會報錯:
main,cpp
#include
#include
intmain()
最後總結一下,我知道我可能對預處理器認識的還不夠清楚,而且很多命令也沒有在這裡談,諸如#pragma(編譯指示指令)、#undef等等,我這也只是看過書之後的有感而發,就是怕自己忘了所以才寫了這篇筆記,如有錯誤還請指正啊*~*。 C 預處理器
偶爾翻c 的教材,看到了一些以前自己不太關注的角落。參考教材 c 大學教程 harvey m.deitel 和paul james deitel著。預處理發生在編譯之前,包括把其他檔案包含到要編譯的檔案中 定義符號常量和巨集 程式 的條件編譯以及預處理指令的條件執行。對應的,預處理指令有 檔案包含命...
C 預處理器
預處理器是一些指令,指示編譯器在實際編譯之前所需完成的預處理。所有的預處理器指令都是以井號 開頭,只有空格字元可以出現在預處理指令之前。預處理指令不是 c 語句,所以它們不會以分號 結尾。我們已經看到,之前所有的例項中都有 include指令。這個巨集用於把頭檔案包含到原始檔中。c 還支援很多預處理...
C 預處理器
預處理器是一些指令,指示編譯器在實際編譯之前所需完成的預處理。所有的預處理器指令都是以井號 開頭,只有空格字元可以出現在預處理指令之前。預處理指令不是 c 語句,所以它們不會以分號 結尾。我們已經看到,之前所有的例項中都有 include指令。這個巨集用於把頭檔案包含到原始檔中。c 還支援很多預處理...