const 跟 literal 的值都不能被改變,看似功能相同,但其本質上的意義還是有落差,我們可以從賦值符號 = 切分為左右邊來認識兩者。
constconst 代表「變數」宣告後不可改變其值,之所以強調「變數」,是因為其仍有自己的名稱跟記憶體位址,位在賦值符號 = 的左邊(左值)。
舉例來說:
const int a = 10;
先來看 = 符號左邊:
const 是修飾符,表示後面接的變數值不能被改變。int 表示變數為整數型別。a 是變數的名稱。這裡已經用 const 表示 a 這個整數變數的值不能修改,因此如果寫:
const int a = 10;
a = 5;
printf("%d", a);
會跑出如下錯誤訊息:
main.c: In function ‘main’:
main.c:14:7: error: assignment of read-only variable ‘a’
14 | a = 5;
|
不過如果要顯示變數 a 的記憶體位址:
const int a = 10;
printf("%p", &a);
是可以正常運作的!
const 不保護型別正當我以為自己清楚已經知道 const 的功能,參加一場面試時卻被問「那型別也能保護嗎?」。當下的我答不出來,只好回家後立刻查資料、做實驗。
後來發現答案是否,例如:
const int a = 10;
float b = (float)a;
printf("%f", b);
是不會報錯的,被 const 保護的 int a 依然被成功轉為 float 型別,可見 const 只能確保變數的「值」不被改變,而不包含型別。
literalliteral 則是單純代表一個固定的值,沒有名稱、也沒有記憶體位址,位在賦值符號 = 的右邊(右值)。
以下寫法都有用到 literal:
const int a = 10;
int a = 10;
= 符號右邊的 10 都是 literal,這兩個 10 都不能再被修改,永遠是 10。
literal 不能取址,因此如果寫:
const int a = 10;
printf("%p", &10);
會跑出:
main.c: In function ‘main’:
main.c:6:18: error: lvalue required as unary ‘&’ operand
6 | printf("%p", &10);
| ^
表示 & 只能對左值(也就是變數)取址。
在剛剛的範例中:
int a = 10;
= 左邊沒有寫 const,看起來可以改啊,怎麼又說值不能改,永遠是 10?
a。10 這個值。在沒有寫 const 的時候,左值可以改、右值不能改;同理左值可以取址、右值不能取址。
而如果要讓左值不能改,就在左邊的 int 前或後加上 const。
現在我們把 const 跟萬惡的指標結合,來看看可以變出什麼花樣。
| 宣告方式 | 指標本身可變(可改指別的) | 指向的值可變 |
|---|---|---|
| const int a;int const a; | 無指標,略 | X |
| const int * a;int const * a; | O | X |
| int * const a; | X | O |
| const * int a; | 無效語法 | 無效語法 |
| const int * const a; | X | X |
透過上表,可以歸納如下:
首先是最簡單的「無指標」情況,代表值不能改。
再來,只要判斷 const 跟誰靠比較近就是修飾誰(表示誰被鎖定不能改):
const 離 int(或其他資料型別)比較近,代表修飾的是指向的值,int 可以寫在 const 的前面或後面,因此寫成 const int * a; 跟 int const *a; 皆可,範例如下:int x = 5, y = 6;
const int *a = &x; // const 貼著 int,表示指向的值不能改
a = &y; // 指標 a 可以從指向 x 的記憶體位址改成指向 y 的記憶體位址
// *a = 7; // 指標 a 指向的值 *a (也就是 5)不能改
const 離 a 比較近,就代表修飾 a 指標本身,指標不能改指其他地方。a 不能寫在 const 前面,所以只會有 int * const a; 一種情況,範例如下:int x = 5, y = 6;
int * const a = &x; // const 貼著 a,表示指標 a 存的位址不能改
// a = &y; // 指標 a 不能改指向 x 之記憶體位址外的其他地方
*a = 7; // 指標 a 指向的值 *a (也就是 5)可以改
const int * const a; 的 int 跟 a 都相鄰於 const,因此指標本身與被指向的值都不能改。
值得留意的是,若 const 沒有跟 int 或 a 相鄰,就是無效語法,例如 const * int a;。