[英]What is the use of intptr_t?
我知道它是一個整數類型,可以在不丟失數據的情況下轉換為/從指針轉換,但我為什么要這樣做? 與用於保存指針的void*
和用於指針算術的THE_REAL_TYPE*
相比,整數類型有什么優勢?
編輯
標記為“已經被問過”的問題沒有回答這個問題。 問題是使用intptr_t
作為void*
的一般替代品是否是一個好主意,並且那里的答案似乎是“不要使用 intptr_t”,所以我的問題仍然有效: intptr_t
好用例是什么?
還有一個語義考慮。
void*
應該指向 something 。 盡管現代實用,指針不是內存地址。 好的,它通常/可能/總是(!)持有一個,但它不是一個數字。 這是一個指針。 它指的是一件事情。
intptr_t
沒有。 它是一個整數值,可以安全地轉換為/從指針轉換,因此您可以將其用於古董 API,將其打包到pthread
函數參數中,諸如此類。
這就是為什么你可以在intptr_t
比在void*
上做的更多和瑣碎的事情,以及為什么你應該通過使用正確的工作類型來進行自我記錄。
最終,幾乎所有東西都可以是整數(請記住,您的計算機可以處理數字!)。 指針可以是整數。 但他們不是。 它們是指針,因為它們的用途不同。 而且,理論上,它們可能不是數字。
該uintptr_t
編寫內存管理代碼時類型是非常有用的。 那種代碼想要通過通用指針 ( void *
) 與它的客戶交談,但在內部對地址進行各種算術運算。
你可以通過操作char *
來做一些相同的事情,但不是所有的,結果看起來像 Ansi C 之前的。
並非所有內存管理代碼都使用uintptr_t
- 例如,BSD 內核代碼定義了一個具有類似屬性的vm_offset_t
。 但是如果你正在編寫一個調試 malloc 包,為什么要發明你自己的類型?
當您的printf
有%p
可用並且正在編寫需要在各種體系結構上以十六進制打印指針大小的整數變量的代碼時,這也很有幫助。
我發現intptr_t
不太有用,除非可能作為轉換時的中轉站,以避免在同一轉換中更改符號和整數大小的可怕警告。 (在所有相關架構上編寫通過-Wall -Werror
可移植代碼可能-Wall -Werror
。)
intptr_t 有什么用?
示例用途:訂單比較。
比較指針是否相等不是問題。
其他比較操作如>, <=
可能是 UB。 C11dr §6.5.8/5 關系運算符。
所以先轉換成intptr_t
。
[編輯] 新示例:按指針值對指針數組進行排序。
int ptr_cmp(const void *a, const void *b) {
intptr_t ia = (intptr) (*((void **) a));
intptr_t ib = (intptr) (*((void **) b));
return (ia > ib) - (ia < ib);
}
void *a[N];
...
qsort(a, sizeof a/sizeof a[0], sizeof a[0], ptr_cmp);
[前一個例子] 示例使用:測試一個指針是否是一個指針數組。
#define N 10
char special[N][1];
// UB as testing order of pointer, not of the same array, is UB.
int test_special1(char *candidate) {
return (candidate >= special[0]) && (candidate <= special[N-1]);
}
// OK - integer compare
int test_special2(char *candidate) {
intptr_t ca = (intptr_t) candidate;
intptr_t mn = (intptr_t) special[0];
intptr_t mx = (intptr_t) special[N-1];
return (ca >= mn) && (ca <= mx);
}
正如@MM所評論的,上面的代碼可能無法按預期工作。 但至少它不是UB。 - 只是不可移植的功能。 我希望用它來解決這個問題。
(u)intptr_t
用於對指針進行算術運算,特別是按位運算。 但正如其他人所說,您幾乎總是想使用uintptr_t
因為按位運算最好在無符號中完成。 但是,如果你需要做一個算術右移則必須使用intptr_t
。 它通常用於在指針中存儲數據,通常稱為標記指針
在 x86-64 中,您可以將高 16/7 位用於數據,但您必須手動進行符號擴展以 使指針規范化,因為它目前沒有 像 ARM 那樣忽略高位的標志。 因此,例如,如果您有char* address
那么您需要在取消引用它之前執行此操作
char* pointer = (char*)((intptr_t)address << 16 >> 16);
32 位 Chrome V8 引擎使用smi(小整數)優化,其中低位表示類型
|----- 32 bits -----| Pointer: |_____address_____w1| # Address to object, w = weak pointer Smi: |___int31_value____0| # Small integer
因此,當指針的最低有效位為 0 時,它將右移以檢索原始的 31 位有符號整數
int v = (intptr_t)address >> 1;
欲了解更多信息,請閱讀
另一種用法是當您將有符號整數作為void*
傳遞時,這通常在回調函數或線程中完成
void* my_thread(void *arg)
{
intptr_t val = (intptr_t)arg;
// Do something
}
int main()
{
pthread_t thread1;
intptr_t some_val = -2;
int r = pthread_create(&thread1, NULL, my_thread, (void*)some_val);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.