欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言中的const如何保證變量不被修改

 更新時間:2021年04月07日 09:27:37   作者:Xilaii  
這篇文章主要給大家介紹了關于C語言中const如何保證變量不被修改的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

這小段文章要理清楚的是,在C語言中,const是如何保證變量不被修改的?

我們可以想到兩種方式:

第一種,由編譯器來阻止修改const變量的語句,讓這種程序不能通過編譯;

第二種,由操作系統(tǒng)來阻止,即把const 的內(nèi)存地址訪問權限標記為“只讀”,一旦運行中的程序試圖修改它,就會產(chǎn)生異常,終止進程。

上面想到的這兩種方式,都能達到讓某一變量的值不被修改的目的,那么究竟是哪一種呢?我們寫兩個例子來看一看。

先來看一個簡單的例子,源文件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”,即“段錯誤”,它是在提醒我們,程序中用錯誤的權限訪問了內(nèi)存某區(qū)域。這說明,操作系統(tǒng)把變量$a$加載到了一段只讀內(nèi)存區(qū)域之中,因此對該區(qū)域地址的寫操作將引發(fā)異常,這是由操作系統(tǒng)的內(nèi)存保護機制決定的。

也就是說,在這段程序里,const的只讀屬性是由操作系統(tǒng)來實現(xiàn)的,而不是由編譯器來實現(xiàn)的(編譯器只拋出了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;”),一旦發(fā)現(xiàn)這種“違背初衷”的語句,就會報錯阻止你。

然而,編譯器所阻止的僅僅是對a這個符號對應值的修改而已,卻并不阻止對這個地址的值的修改,源文件“const2.c”之所以能順利通過編譯且正常運行,就是因為它利用一個名字不叫a的指針指向它,從而繞過了編譯器的語法檢查。

打個比方,周樹人的筆名叫魯迅,警察只知道要抓魯迅,這時候他就可以用一句“你們抓魯迅跟我周樹人有什么關系?”來騙過他們。

從這個角度來說,const的作用是靠編譯器僅僅從語法檢查來實現(xiàn)的,因此存在運行時的漏洞。

那么為什么“const1.c”就不能正常運行呢?

仔細看這兩個源程序,區(qū)別僅僅在于,在“const1.c”中,a被聲明為全局變量,而在“const2.c”中,它被聲明為main函數(shù)中的一個局部變量。全局變量與局部變量的區(qū)別在于,前者會在程序開始運行之前就被加載,加載后會一直留在內(nèi)存中,且加載的位置在數(shù)據(jù)區(qū),直到程序退出;后者只有在運行到它時才會被加載,且加載的位置是運行時的棧幀,一旦超出作用于就會被回收。

因此,編譯器會對被聲明為全局變量的const int a進行優(yōu)化,把它放到只讀內(nèi)存區(qū)內(nèi),這一內(nèi)存區(qū)的權限是“read\ only”,權限信息由操作系統(tǒng)所維護的段表來保存,程序每訪問某地址時,操作系統(tǒng)都會檢測其訪問權限是否合法?!癱onst2.c”中企圖用“寫”的方式來訪問“只讀”的段,自然會報出“segment fault"的錯了。

從這個角度來說,當a是全局變量時,編譯器把原本只是“不打算修改的變量”優(yōu)化成了“真正的常量”,然后交給操作系統(tǒng)去維持其不變屬性。

綜上所述,C的初衷只是讓編譯器去保證$const$的不變屬性,這一屬性有漏洞(可以用指針去騙過編譯器修改它),所以當const修飾的對象是全局變量時(全局變量很重要,因為很多源文件都要訪問它,牽一發(fā)而動全身,所以不應輕易更改),編譯器知道自己的能力有限,只能管得了編譯,管不了運行時如何,所以優(yōu)化了語句把它編程真正的常量,讓操作系統(tǒng)的內(nèi)存保護功能來履行這一職責。

這一優(yōu)化,并不是C規(guī)定的,而是編譯器廠商出于實際應用的考慮作出的選擇。

以上,是我根據(jù)編譯器和程序運行時的行為所做的推測,這一思路并不妥當,只是我在編程時遇到了上述兩個例子的困惑,又沒找到說得很清楚的資料,所以就寫出來了,若要進一步驗證,應該查看編譯后的可執(zhí)行文件分段情況,我偷了個懶沒看,暫時放在這里。

如果推測不正確,希望有前輩指出。

總結

到此這篇關于C語言中const如何保證變量不被修改的文章就介紹到這了,更多相關C語言const變量不修改內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 總結了24個C++的大坑,你能躲過幾個

    總結了24個C++的大坑,你能躲過幾個

    這篇文章主要介紹了總結了24個C++的大坑,你能躲過幾個,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-05-05
  • C++ OpenCV實現(xiàn)與添加椒鹽噪聲和高斯噪音

    C++ OpenCV實現(xiàn)與添加椒鹽噪聲和高斯噪音

    圖像噪聲是圖像在獲取或是傳輸過程中受到隨機信號干擾,妨礙人們對圖像理解及分析處理的信號,本文為大家整理了C++結合OpenCV為圖像添加椒鹽噪聲和高斯噪音的代碼,需要的可以收藏一下
    2023-09-09
  • C++設計模式之組合模式(Composite)

    C++設計模式之組合模式(Composite)

    這篇文章主要為大家詳細介紹了C++設計模式之組合模式Composite,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • C++中的最小生成樹算法超詳細教程

    C++中的最小生成樹算法超詳細教程

    這篇文章主要介紹了C++中的最小生成樹算法超詳細教程,最小生成樹的最著名的算法有兩個, 一個是Prim算法, 另一個當然就是Kruskal算法, 接下來, 我將盡我所能的介紹這兩個算法, 也算是對自己學習的一個回顧吧,需要的朋友可以參考下
    2023-08-08
  • c語言打開文件函數(shù)使用方法

    c語言打開文件函數(shù)使用方法

    這篇文章主要介紹了c語言打開文件函數(shù)使用方法,需要的朋友可以參考下
    2014-02-02
  • C++深入學習之徹底理清重載函數(shù)匹配

    C++深入學習之徹底理清重載函數(shù)匹配

    C++ 不允許變量重名,但是允許多個函數(shù)取相同的名字,只要參數(shù)表不同即可,這叫作函數(shù)的重載,下面這篇文章主要給大家介紹了關于C++深入學習之徹底理清重載函數(shù)匹配的相關資料,需要的朋友可以參考下
    2019-01-01
  • C++之智能指針初步及棄用auto_ptr的原因分析

    C++之智能指針初步及棄用auto_ptr的原因分析

    這篇文章主要介紹了C++之智能指針初步及棄用auto_ptr的原因分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • c++創(chuàng)建二維動態(tài)數(shù)組與內(nèi)存釋放問題

    c++創(chuàng)建二維動態(tài)數(shù)組與內(nèi)存釋放問題

    這篇文章主要介紹了c++創(chuàng)建二維動態(tài)數(shù)組與內(nèi)存釋放問題,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06
  • C++中對象的賦值與復制操作詳細解析

    C++中對象的賦值與復制操作詳細解析

    對象之間的賦值也是通過賦值運算符“=”進行的。本來賦值運算符“=”只能用來對單個的變量賦值,現(xiàn)在被擴展為兩個同類對象之間的賦值,這是通過對賦值運算符的重載實現(xiàn)的
    2013-10-10
  • C++基于棧的深搜算法實現(xiàn)馬踏棋盤

    C++基于棧的深搜算法實現(xiàn)馬踏棋盤

    這篇文章主要為大家詳細介紹了C++基于棧的深搜算法實現(xiàn)馬踏棋盤,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評論