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

C++ Primer 指針相等邊界情況:相鄰對象導致指針值相等的內存佈局解析

     編輯:程式設計疑難解答

《C++ Primer》第 5 版 P50 指出:一個指針指向某對象,另一個指針指向「另一對象的下一地址」,此時兩指針可能相等。這看似矛盾實則揭示了 C++ 對象模型與指針算術的深層邏輯。本文通過內存佈局圖解徹底講透。

核心結論

「另一對象」與「某對象」在內存中恰好相鄰,且「另一對象」緊挨在「某對象」之前。此時「另一對象的下一地址」即「某對象的起始地址」,兩指針值相等。

內存佈局圖解

假設對象 A (int, 4字節) 與 對象 B (int, 4字節) 在棧上相鄰分配,B 在低地址,A 在高地址:

地址:   0x1000    0x1004    0x1008
        +--------+--------+
        |   B    |   A    |   ← 內存佈局(棧向下增長時反過來,邏輯相同)
        +--------+--------+
                ↑
指針 p1 = &A;           // 指向「某對象」A 的起始地址 0x1004
指針 p2 = &B + 1;       // 指向「另一對象」B 的「下一地址」= 0x1000 + sizeof(B) = 0x1004

結果:p1 == p2 為 true

關鍵知識點

  1. 指針算術:ptr + n 表示向後偏移 n * sizeof(T) 字節。&B + 1 指向緊隨 B 之後的 T 類型對象位置(即「下一個」假想對象的起始地址)。
  2. 標準保證:標準允許指針指向「數組最後一個元素之後」或「單個對象之後」的地址(稱為「一過去尾指針」),但**解引用該指針屬於未定義行為(UB)**。
  3. 對象相鄰不保證:編譯器可能因對齊、優化插入填充字節,導致相鄰聲明的對象在內存中不相鄰。上述相等屬「可能發生」,非「必然發生」。
  4. 比較合法性:指向同一數組/對象(或一過去尾)的指針比較合法;指向無關對象的指針比較結果未規定(C++11 起可比較地址值,但語義薄弱)。

實戰警示

  • **切勿利用此特性編程**;代碼可移植性極差,極易因編譯器版本、優化等級、鏈接順序變化而失效。
  • 正確做法:用 std::addressof 獲取地址,用 std::uintptr_t 比較數值,或重新設計數據結構(如用數組/結構體確保佈局)。
  • 調試時若遇到「莫名相等的指針」,檢查是否為一過去尾指針與相鄰對象起始地址重合。

延伸:數組與一過去尾指針

int arr[3] = {1,2,3};
int *p1 = &arr[2];      // 指向最後一個元素
int *p2 = arr + 3;      // 一過去尾指針
// p1 + 1 == p2  為 true
// *p2  是 UB!

理解此邊界情況,有助於深入掌握 C++ 指針語義、迭代器失效規則及標準庫算法(如 std::sort(begin, end) 中 end 即一過去尾)的設計哲學。

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