[英]ptrdiff_t too small?
我一直在想:是不是ptrdiff_t
應該能夠舉辦任何兩個指針定義的區別? 當兩個指針太遠時怎么會失敗呢? (我沒有指出任何特定語言......我指的是所有具有此類型的語言。)
(例如,當你有32位指針時,用地址0xFFFFFFFF
從字節指針中減去帶地址1
的指針,它會溢出符號位...)
不它不是。
$ 5.7 [expr.add] (來自n3225 - C ++ 0x FCD)
當減去指向同一數組對象的元素的兩個指針時,結果是兩個數組元素的下標的差異。 結果的類型是實現定義的有符號整數類型; 此類型應與<cstddef>
標頭(18.2)中定義為std::ptrdiff_t
類型相同。 與任何其他算術溢出一樣,如果結果不適合所提供的空間,則行為未定義。 換句話說,如果表達式P
和Q
分別指向數組對象的第i
和第j
個元素,則表達式(P)-(Q)
具有值i − j
條件是該值適合於std::ptrdiff_t
類型的對象。 此外,如果表達式P
指向數組對象的元素或者指向數組對象的最后一個元素,並且表達式Q
指向同一數組對象的最后一個元素,則表達式((Q)+1)-(P)
具有與((Q)-(P))+1
和-((P)-((Q)+1))
的值,並且如果表達式P
指向一個,則值為零數組對象的最后一個元素,即使表達式(Q)+1
沒有指向數組對象的元素。 除非兩個指針指向同一個數組對象的元素,或者指向數組對象的最后一個元素,否則行為是未定義的。
請注意段落中出現undefined
的次數。 另請注意,如果指針指向同一對象,則只能減去指針。
不,因為沒有“任何兩個指針”之間的區別。 您只能減去指向同一數組元素的指針(或指向剛好超過數組末尾的位置的指針)。
要添加更明確的標准引用, ISO 9899:1999 §J.2/1
規定:
在以下情況下,行為未定義:
[...]
- 減去兩個指針的結果在ptrdiff_t(6.5.6)類型的對象中無法表示。
ptrdiff_t
與指針類型的大小完全相同,只要溢出語義由編譯器定義,這樣任何差異仍然可以表示。 無法保證負ptrdiff_t意味着第二個指針位於內存中比第一個更低的地址,或ptrdiff_t根本沒有簽名。
對於固定大小的整數運算,上/下溢在數學上是明確定義的:
(1 - 0xFFFFFFFF) % (1<<32) =
(1 + -0xFFFFFFFF) % (1<<32) =
1 + (-0xFFFFFFFF % (1<<32)) = 2
這是正確的結果!
具體來說,上溢/下溢后的結果是正確整數的別名。 事實上,每個不可表示的整數都有一個可表示的整數別名(無法區分) - 在固定大小的整數中計數到無窮大,你會像模擬時鍾的表盤一樣重復自己,圓形和圓形。
N位整數表示模2 ^ N的任何實數。 在C中,模2 ^ N寫為%(1 << 32)。
我相信C保證上溢/下溢的數學正確性,但僅適用於無符號整數。 假設簽名在/溢出下永遠不會發生(為了優化)。
在實踐中,有符號整數是兩個補碼,這在加法或減法中沒有區別,因此對於有符號整數也保證正確的欠/溢出行為(盡管不是由C)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.