[英]What is the motivation for ptrdiff_t?
為什么 C 為兩個指針之間的差異定義一個單獨的類型? 例如,為什么不能將其定義為long long
,甚至不能定義為intmax_t
? 是否有過intmax_t
不等於ptrdiff_t
的時候?
基本上,為什么這個 typedef(具有特定的字符串格式等)有用是什么意思? 作為一個基本的使用示例,我正在做:
int a = 1, b = 2;
printf("%td XXX\n", (char *)(&b) - (char *)(&a)); // 't' is formatter for prtdiff_t
是否有過
intmax_t
不等於ptrdiff_t
的時候?
是的,在指針為 32 位且intmax_t
>=64 位的 32 位平台上。
這是 C 標准中的相關段落:
6.5.6 加法運算符
[...]
語義
[...]
9.當兩個指針相減時,都指向同一個數組object的元素,或者數組object的最后一個元素; 結果是兩個數組元素的下標之差。 結果的大小是實現定義的,其類型(帶符號的 integer 類型)是在<stddef.h>
header 中定義的ptrdiff_t
。 如果結果在該類型的 object 中不可表示,則行為未定義。 換句話說,如果表達式P
和Q
分別指向數組 object 的第i
個和第j
個元素,則表達式(P)-(Q)
的值是i - j
,前提是該值適合Ptrdiff_t 類型的ptrdiff_t
。 此外,如果表達式P
指向數組 object 的元素或數組 object 的最后一個元素,並且表達式Q
指向同一數組 object 的最后一個元素,則表達式((Q)+1)-(P)
與((Q)-(P))+1
和-((P)-((Q)+1))
具有相同的值,並且如果表達式P
指向超過數組 object 的最后一個元素,即使表達式(Q)+1
不指向數組 object 的元素。 108)
108) 處理指針運算的另一種方法是首先將指針轉換為字符指針:在此方案中,在轉換后的指針中添加或減去的 integer 表達式首先乘以最初指向的 object 的大小, 並將結果指針轉換回原始類型。 對於指針減法,字符指針之間的差異結果同樣除以最初指向的 object 的大小。 以這種方式查看時,實現只需在 object 結束后提供一個額外字節(可能與程序中的另一個 object 重疊)以滿足“過去最后一個元素”的要求。
盡管 C 標准沒有強制要求,但ptrdiff_t
通常定義為簽名的 integer 類型,大小與size_t
相同。 On architectures where the maximum size of an object is limited to 32 bits, such as 32-bit Windows and Unix systems, size_t
is an unsigned 32-bit integer type and ptrdiff_t
a signed 32-bit integer type, whereas on 64-bit systems具有更大的地址空間,它們都是 64 位 integer 類型,對ptrdiff_t
有符號,對size_t
無符號。
但是請注意,兩個指針指向一個非常大的char
數組的差異可能會超出與size_t
大小相同的有符號類型的范圍。 例如,3GB char 數組可能在 32 位系統上可用( UINT32_MAX
> 3GB),但 2 個指針的絕對值之差可以大到 3GB,這超出了int32_t
的范圍,因此適合ptrdiff_t
類型這個平台的,調用未定義的行為。
大多數實現通過減去地址並將結果除以元素大小來獲得差異,如果大小是 2 的冪,則使用有符號算術或有符號右移。對於大於char
的大型 arrays 元素,這可能會產生不正確的結果,即使該值適合ptrdiff_t
類型的 object 。
使用實現定義類型ptrdiff_t
而不是long long
的基本原理是保持與現有實現的兼容性,並避免在地址空間較小的系統上使用較大的類型,這會導致空間和時間的額外開銷。 在早期的 C 實現中,類型int
用於此目的,並且當size_t
引入的范圍可能與unsigned int
不同時,由於int
太小,因此需要用於 2 個指針差異的特定類型。 ptrdiff_t
可能仍然太小,但僅適用於邊界情況。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.