不一樣的C語言-const修飾的變量

const修飾的變量

上一篇文章中,筆者講了auto,register,static,extern修飾符對變量的作用,那麼本文中,我們繼續來介紹變量的修飾符--const。const是constant的縮寫,意爲:常量。當變量前面加上const修飾,此時這個變量是一個只讀變量。這裏應當注意的是,變量還是變量,只不過變量具有了只讀的屬性。下文中筆者會通過幾個簡單的例子來分析const修飾符。

一、const修飾基本局部變量

以int類型爲例,我們來看看const修飾基本類型變量時,變量會有什麼變化。

const int i = 0;
i = 10;

上訴的代碼,編譯時會發生錯誤。原因很簡單,我們使用const修飾了變量 i ,此時變量 i 就是一個只讀變量,只讀變量在初始化之後,不能作爲左值。那麼是否就說明 i 所指向的內存空間就是安全的呢?我們繼續看一個例子:

int *p = &i;
*p = 10;
printf("%d',i);

我們說了,i 現在是一個只讀變量,不能作爲左值,那出現的賦值號的右邊總沒問題吧,否則就是失去了變量的意義了。既然是合法的,我們試圖來解釋“int *p = &i”這句的含義,p是一個int類型的指針,指向了變量 i 的內存地址,那麼p就指向了變量 i 的內存空間。順利成章的我們通過p來修改 i 的內存空間爲10,那麼 i 對應的內存空間就應該爲10。事實確實如此,如此看來,這個const有點雞肋。我們先不着急去評判const的是否值得存在,我們來看看const修飾指針會發生什麼有趣的事情。

二、const修飾的全局變量

const修飾的全局變量和局部變量不同,可以說,const修飾的全局變量是一個常量,其存放在只讀數據區(rodata),也就是說const修飾的全局變量的內存空間是隻讀的,當我們試圖通過任何方式去修改,都是使得程序出錯崩潰。

include <stdio.h>
const int i = 0;
int main()
{
    int *p = &i;
    *p = 10;
    printf("%d",i);
    return 0;
}

上述代碼編譯時也許編譯器不會給你報錯,但是運行起來,程序就會出錯崩潰,所以不要嘗試去修改全局只讀變量(常量)。

三、const與指針相遇

int i = 0;
const int *p = &i;
*p = 10;

把*p看做一個整體A,“const int A”定義了一個只讀變量A,然後“A = 10”,顯然,這就發生了錯誤,我們試圖改變一個只讀變量。由此,上面的那段代碼編譯會報錯。接下來我們繼續看一個例子:
int i = 0;
int * const p = &i;
*p = 10;

上述的代碼,編譯會出錯嗎?答案是不會。原因在於,const修飾的是p,p是指針,也就是說,p的值不能被改變,但是我們操作*p是可以的,*p指代的是變量 i 的內存空間。到此,讀者可能對const的認識已經足夠好了,那麼我們繼續看一個更有趣的例子:
typedef int* pint;
int main()
{
    int i = 0;
    const pint p = &i;
    *p = 10;
    
    return 0;
}

這次編譯能否通過,同樣不下定論,先分析。可能很多讀者會把上上個例子拿出來看,“const pint p”相當於“const int *p”,這個我們相當熟悉嗎,上上個例子就講過了,結論是我們無法修改*p。錯!別忘記了筆者還寫過一個重要的技巧“把類型忽略來看待”,typedef想必大家熟悉,爲類型起一個別名。那麼此時pint就是一個類型別名,“const pint p”我們忽略類型pint,剩下“const p”,這下撥開烏雲見藍天了把。const修飾的是變量p,與*p沒關係,所以編譯是正確的。

總結:

C語言的const,對於局部變量而言,是將一個變量修飾爲只讀變量,既然是一個變量,那麼其依然可以變,只不過我們不能通過已經被const修飾的變量名來修改。對於全局變量而言,其修飾的變量保存在代碼段的rodata,這段內存是隻讀的,所以const修飾的全變量是真正意義上的常量。對於const修飾的對象究竟是誰,可以借鑑筆者上面說的忽略類型名的方法,化繁爲簡來看。顯然const可以減少由於程序員的疏忽而改變了一個原本不打算改變的量,在編譯的時候就能夠發現。當然const不能將居心叵測的程序員拒之門外(C++中就不是如此,另當別論)。

發佈了28 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章