您好,登錄后才能下訂單哦!
小編給大家分享一下C語言中const保證變量不被修改的方法有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
在C語言中,const是如何保證變量不被修改的?
我們可以想到兩種方式:
第一種,由編譯器來阻止修改const變量的語句,讓這種程序不能通過編譯;
第二種,由操作系統來阻止,即把const 的內存地址訪問權限標記為“只讀”,一旦運行中的程序試圖修改它,就會產生異常,終止進程。
上面想到的這兩種方式,都能達到讓某一變量的值不被修改的目的,那么究竟是哪一種呢?我們寫兩個例子來看一看。
先來看一個簡單的例子,源文件const.c:
#include <stdio.h> const int a=10; int main() { int *p=&a; printf("initial: %d\n",a); *p=1; printf("modified: %d\n",a); return 0; }
編譯,會收到一個 warning:
$ gcc -o const1 const1.c
const.c: In function ‘main':
const.c:7:12: warning: initialization discards ‘const' qualifier from pointer target type [-Wdiscarded-qualifiers]
int *p=&a;
忽略之,運行程序:
$ ./const1
initial: 10
Segmentation fault (core dumped)
運行出錯了,報錯是“segmentation fault”,即“段錯誤”,它是在提醒我們,程序中用錯誤的權限訪問了內存某區域。這說明,操作系統把變量$a$加載到了一段只讀內存區域之中,因此對該區域地址的寫操作將引發異常,這是由操作系統的內存保護機制決定的。
也就是說,在這段程序里,const的只讀屬性是由操作系統來實現的,而不是由編譯器來實現的(編譯器只拋出了warning,并沒有阻止編譯通過)。
這對嗎?不完全對,我們來看另一個例子,源文件const2.c:
#include <stdio.h> int main() { const int a=10; int *p=&a; printf("initial: %d\n",a); *p=1; printf("modified: %d\n",a); return 0; }
編譯,還是收到同樣的warning:
$ gcc -o const2 const2.c
const.c: In function ‘main':
const.c:6:12: warning: initialization discards ‘const' qualifier from pointer target type [-Wdiscarded-qualifiers]
int *p=&a;
忽略之,運行程序:
./const2
initial: 10
modified: 1
咦?怎么成功運行了,而且a的值還被順利修改了?
結合以上兩個例子,我們可以得出以下推測:
const只是C語言中的一種對變量的修飾符,例子中的a,與其說是“常量”,不如說是“不打算修改的變量”。它只是語法上的一種聲明,它的作用就是告訴編譯器“我不想修改它”,因此編譯器會從語法上檢查程序中是否有修改它的語句(例如“a=1;”),一旦發現這種“違背初衷”的語句,就會報錯阻止你。
然而,編譯器所阻止的僅僅是對a這個符號對應值的修改而已,卻并不阻止對這個地址的值的修改,源文件“const2.c”之所以能順利通過編譯且正常運行,就是因為它利用一個名字不叫a的指針指向它,從而繞過了編譯器的語法檢查。
打個比方,周樹人的筆名叫魯迅,警察只知道要抓魯迅,這時候他就可以用一句“你們抓魯迅跟我周樹人有什么關系?”來騙過他們。
從這個角度來說,const的作用是靠編譯器僅僅從語法檢查來實現的,因此存在運行時的漏洞。
那么為什么“const1.c”就不能正常運行呢?
仔細看這兩個源程序,區別僅僅在于,在“const1.c”中,a被聲明為全局變量,而在“const2.c”中,它被聲明為main函數中的一個局部變量。全局變量與局部變量的區別在于,前者會在程序開始運行之前就被加載,加載后會一直留在內存中,且加載的位置在數據區,直到程序退出;后者只有在運行到它時才會被加載,且加載的位置是運行時的棧幀,一旦超出作用于就會被回收。
因此,編譯器會對被聲明為全局變量的const int a進行優化,把它放到只讀內存區內,這一內存區的權限是“read\ only”,權限信息由操作系統所維護的段表來保存,程序每訪問某地址時,操作系統都會檢測其訪問權限是否合法。“const2.c”中企圖用“寫”的方式來訪問“只讀”的段,自然會報出“segment fault"的錯了。
從這個角度來說,當a是全局變量時,編譯器把原本只是“不打算修改的變量”優化成了“真正的常量”,然后交給操作系統去維持其不變屬性。
綜上所述,C的初衷只是讓編譯器去保證$const$的不變屬性,這一屬性有漏洞(可以用指針去騙過編譯器修改它),所以當const修飾的對象是全局變量時(全局變量很重要,因為很多源文件都要訪問它,牽一發而動全身,所以不應輕易更改),編譯器知道自己的能力有限,只能管得了編譯,管不了運行時如何,所以優化了語句把它編程真正的常量,讓操作系統的內存保護功能來履行這一職責。
這一優化,并不是C規定的,而是編譯器廠商出于實際應用的考慮作出的選擇。
以上是“C語言中const保證變量不被修改的方法有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。