1. 程式人生 > 其它 >const修飾符並不保證執行時的常數性質

const修飾符並不保證執行時的常數性質

技術標籤:筆記C/C++c++編譯器

∇ \nabla 聯絡方式:

e-mail: [email protected]

QQ: 973926198

github: https://github.com/FesianXu

知乎專欄: 計算機視覺/計算機圖形理論與應用

微信公眾號


constvolatile修飾符統稱為cv修飾符,用於指示編譯器是否允許一個程式中的某個變數的記憶體是否在初始化後,仍允許被修改。其中的volatile我們已經在前文[1]中討論過了,我們討論下const的一些特性。我們知道,cv修飾符都是給編譯器看的,用於指導編譯過程中的優化(如volatile)或者使用者非法變數修改行為(如const

),因此這倆個修飾符只能保證編譯時的操作合乎設計時候的需求,但是如果涉及到執行時(running time)的一些操作,是無法保證的。我們本文討論const修飾後的變數,被執行時『修改』的例子。

如果我們正常使用const,理應如下所示:

const int var = 10;
int var_b = 100;

var = 100; // 非法操作,因為var是const型別,初始化後不能被修改。
var_b = 10; // 合法操作,正常的賦值

然而,我們不能確保執行時,被const修飾的變數記憶體,被其他程式,或者自行設計錯誤,或者黑客行為修改,舉個例:

#include <stdio.h>
int main(void) { int a = 10; const int b = 9; int c = 8; printf("%d\t%d\t%d\n\r", a, b, c); int* pa = &a; const int* pb = &b; int* pc = &c; printf("%x\t%x\t%x\n\r", pa,pb,pc); *(pa+1) = 100; // modify the first time printf("%d\n\r", *(pa+1)); *(pc-
1) = 300; printf("%x\t%x\t\n\r", (pa+1), (pc-1)); printf("%d\n\r", (pa+1) == (pc-1)); printf("%d\n\r", (pa+1) == pb); printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,*(pb)); return 0; }

g++ test_const.cpp編譯,用./a.out輸出結果,程式碼輸出為:
在這裡插入圖片描述

我們可以發現,通過棧[2]上相鄰的變數的地址做偏移,可以實現間接地對const修飾的變數進行修改,這種行為會意料之外的修改常量,非常的危險,我們的程式碼中需要檢查涉及到指標偏移的操作,檢查是否會出現越界的情況。

注意到,如果程式碼中的輸出從:

printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,*(pb));

改成

printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,b);

結果是不一樣的,後者的結果仍然是輸出b = 9,那是因為C++在編譯時對常量進行摺疊,因此直接輸出3這個立即數了,而不是從記憶體裡面取出常量再輸出,這一點要注意。


Reference

[1]. https://blog.csdn.net/LoseInVain/article/details/103356324
[2]. https://blog.csdn.net/LoseInVain/article/details/103183829