首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ const 與指標運算:為何同一記憶體位址出現兩個不同值?

     編輯:程式設計綜合問答

現象重現

const int i = 10;
int j;
int *p = &j;
p++;
*p = 20;
j = i;
cout << p << \" \" << *p << endl; // 0012FF44 20
cout << &i << \" \" << i << endl;   // 0012FF44 10
cout << &j << \" \" << j << endl;   // 0012FF40 10

輸出顯示 p 與 &i 位址相同(0012FF44),但 *p=20、i=10 值不同。

深層原因

  1. 未定義行為(UB):p++ 使指標超出 j 的合法範圍,隨後寫入 *p=20 屬於**越界寫入**,行為不可預期。
  2. 編譯器優化與常數傳播:const int i=10 讓編譯器將 i 視為編譯期常數,直接內嵌 10 到機器碼,**不讀取記憶體**。即使記憶體被改寫,cout<<i 仍輸出 10。
  3. 棧佈局巧合:在該編譯器/優化等級下,i 與 j 相鄰,p++ 剛好落在 i 的位址,但這**不具可移植性**,換編譯器/優化等級位址關係即改變。

實驗驗證

const int xyz = 3333;
const int i = 123;
int j = 321;
int *p = &j;
p++; *p = 13; // 嘗試修改 i 位址
cout << p << *p << endl; // 印出 3333 (xyz) 而非 13
cout << &i << i << endl; // 仍印 123

顯示編譯器將 i 視為唯讀常數區,**實際寫入的是鄰近的另一常數 xyz**,且 i 的值因常數傳播未變。

標準規定

  • C++ 標準:修改 const 物件為未定義行為(C++17 [dcl.type.cv])。
  • 指標運算超出物件邊界(含一個元素後)亦為 UB。

正確做法

  • 需要可修改的變數,**勿加 const**。
  • 若需常數語意但可在執行期決定值,用 constexpr 或 const 但**不嘗試透過指標修改**。
  • 嚴禁對 const 物件做 const_cast 後寫入,除非確知原物件非真正常數(如硬體暫存器映射)。

結論:**同一位址兩值**是 UB + 編譯器常數傳播 + 棧佈局巧合共同造就的假象,不可依賴、不可複製。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved