常量是在程序中不能更改的量,在C/C++中有兩種方式定義常量,一種是利用define宏定義的方式,一種是C++中新提出來的const型常變量,下面主要討論它們之間的相關問題;
define定義的常量:
define是預處理指令的一種,它用來定義宏,宏只是一個簡單的替換,將宏變量所對應的值替換,如下面的代碼:
#define NUM 2 int main() { printf("%d", NUM); }
編譯器在編譯時處理的並不是這樣的代碼,編譯器會首先處理預處理指令,根據預處理指令生成相關的代碼文件,然后編譯這個文件,得到相關的.obj文件,最后通過鏈接相關的.obj文件得到一個可執行文件,最典型的是我們一般在.cpp文件中寫的#include指令,在處理時首先將所需包含的頭文件整個拷貝到這個.cpp文件中,並替換這個#include指令,然后再編譯生成的文件,這個中間文件在Windows中后綴為.i,在Visual C++ 6.0中以此點擊Project-->Settings-->C/C++,在Project Options最后一行加上'/P'(P為大寫)這樣在點擊編譯按鈕時不會編譯生成obj文件,只會生成.i文件,通過這個.i文件可以看到在做預處理的時候會將 NUM替換成2然后在做編譯處理,這個時候點擊生成時會出錯,因為我們將編譯選項修改后沒有生成.obj文件但是在生成時需要這個文件,因此會報錯,所以在生成時要去掉這個/P選項。而我們看到在使用const 定義的時候並沒有這個替換的操作,與使用正常的變量無異。const型變量只是在語法層面上限定這個變量的值不可以修改,我們可以通過強制類型轉化或者通過內嵌匯編的形式修改這個變量的值,比如下面的代碼:
int main(int argc, char* argv[]) { const nNum = 10; int *pNum = (int*)&nNum; printf("%d\n", nNum); return 0; }
const nNum = 10; __asm { mov [ebp - 4], 10 } printf("%d\n", nNum); return 0;
但是我們看到,這兩種方式修改后,輸出的值仍然是10,這個原因我們可以通過查看反匯編代碼查看
;printf("%d\n", nNum); 00401036 push 0Ah 00401038 push offset string "%d\n" (0042001c) 0040103D call printf (00401070) 00401042 add esp,8
在調用printf的時候,入棧的參數是10,根本沒有取nNum值得相關操作,在利用const定義的常量時,編譯器認為既然這是一個常量,應該不會修改,為了提升效率,在使用時並不會去對應的內存中尋址,而是直接將它替換為初始化時的值,為了防止這種事情的發生,可以利用C++中的關鍵字:volatile。這個關鍵字保證每次在使用變量時都去內存中讀取。
我們可以總結出const和define的幾個不同之處:
1)define是一個預處理指令,const是一個關鍵字。
2)define定義的常量編譯器不會進行任何檢查,const定義的常量編譯器會進行類型檢查,相對來說比define更安全
3)define的宏在使用時是替換不占內存,而const則是一個變量,占內存空間
4)define定義的宏在代碼段中不可尋址,const定義的常量是可以尋址的,在數據段或者棧段中。
5)define定義的宏在編譯前的預處理操作時進行替換,而const定義變量是在編譯時決定
6)define定義的宏是真實的常量,不會被修改,const定義的實際上是一個變量,可以通過相關的手段進行修改。