C++深度解析 進化後的const分析(2)
C++深度解析 進化後的const分析(2)
1 C語言中的const變數
C語言中的const變數是只讀變數,其本質還是變數,會分配儲存空間。(通過列舉enum定義真正的常量)
由於const區域性變數會存放在棧裡,而const全域性變數會存在只讀儲存記憶體上。
所以我們可以通過指標來修改const區域性變數,但是修改const全域性變數,會使程式崩潰
示例1:
通過指標來修改const區域性變數
#include <stdio.h> int main() { const int c = 0; //const區域性變數 int* p = (int *)&c; //通過指標修改const變數 *p = 5; printf("c = %d\n", c); return 0; }
輸出結果:
示例2:
#include <stdio.h>
const int c = 0; //const全域性變數
int main()
{
int* p = (int *)&c; //通過指標修改const變數
*p = 5;
printf("c = %d\n", c);
return 0;
}
輸出結果:
由於指標修改只讀儲存區的資料,所以導致程式崩潰。
2 C++中的const常量
在C++中,const變數則是真正的常量了,定義時會將其放入符號表中。
所以編譯途中遇到使用const變數時,則直接從符號表中取出常量
只要當該const變數為全域性(使用extern宣告過),或者被使用&操作符時,才會被分配儲存空間。
示例程式碼:
#include <stdio.h>
int main()
{
const int c = 0; //const區域性變數
int* p = (int *)&c; //使用&操作符,會分配空間
*p = 5;
printf("c = %d, p=%d\n", c, *p);
return 0;
}
結果如下:
為什麼輸出結果會有兩個不同的值?
這是因為使用&c時,會從符號表中取出c的值,並將0存在一個新的分配空間地址
3 符號表
就是編譯器在編譯過程過程中產生的一張表。(符號表是編譯器的內部結構)
所以為c分配的4位元組的空間,毫無意義。只是為了相容c語言。
//將常量c(識別符號)存入符號表
const int c = 0;
//為識別符號c分配4個位元組空間,並不使用
int* p = (int *)&c;
printf("Begin...\n");
//修改的是編譯器為識別符號c分配的空間
*p = 5;
//編譯器會檢視符號表,發現裡面c,值是c
printf("c = %d\n", c);
printf("End...\n");
4 C++的const 和 巨集定義
4.1 C++中的的const常量類似於巨集定義
const int c = 5; ≈ define c 5
4.2 C++中的const常量在與巨集定義不同
const常量是由編譯器處理,編譯器對const常量進行型別檢查和作用域檢查。
define巨集定義由前處理器處理,單純的文字替換,不會進行各種檢查
(前處理器是執行編譯器之前執行的程式,用來刪減註釋,巨集變數轉換等)
示例程式碼:
#include <stdio.h>
void f()
{
//巨集是被前處理器處理的,直接進行文字替換
#define a 3 //定義巨集
const int b = 4;//定義區域性變數
}
void g()
{
printf("a = %d\n", a); //a=3
//printf("b = %d\n", b); //b的作用域f(),在f之外是不能訪問b
}
int main()
{
const int A = 1;
const int B = 2;
//從符號表中取出數值
int array [A + B] = {0};
int i = 0;
for(i = 0; i < (A+B); i++)
{
printf("array[%d] = %d\n", i, array[i]);
}
f();
g();
return 0;
}
因為執行前處理器時,會將預見到的所有a變為3,所以編譯器看到的是printf("a = %d", 3);
而取消//printf("b = %d\n", b);遮蔽後,程式則會報錯,是因為b的作用域只在f()函式裡有效
5 小結:
C++中的const是一個真正意義上的常量
C++編譯器可能會為constchan常量分配空間
C++完全相容Cyu'y語言中const常量的語法特性