[英]printf("%p") and casting to (void *)
在最近的一個問題中,有人提到在使用 printf 打印指針值時,調用者必須將指針強制轉換為 void *,如下所示:
int *my_ptr = ....
printf("My pointer is: %p", (void *)my_ptr);
對於我的生活,我無法弄清楚為什么。 我發現了這個問題,這幾乎是一樣的。 問題的答案是正確的 - 它解釋了整數和指針的長度不一定相同。
這當然是真的,但是當我已經有一個指針時,就像上面的例子一樣,為什么我應該從int *
為void *
? 什么時候 int * 與 void * 不同? 事實上, (void *)my_ptr
什么(void *)my_ptr
生成任何不同於my_ptr
機器代碼?
更新:多個知識淵博的響應者引用了該標准,稱傳遞錯誤的類型可能會導致未定義的行為。 如何? 我希望printf("%p", (int *)ptr)
和printf("%p", (void *)ptr)
生成完全相同的堆棧幀。 兩個調用何時會生成不同的堆棧幀?
%p
轉換說明符需要一個void *
類型的參數。 如果您不傳遞類型為void *
的參數,則函數調用會調用未定義的行為。
來自 C 標准(C11,7.21.6.1p8 格式化輸入/輸出函數):
“p - 參數應是指向 void 的指針。”
C 中的指針類型不需要具有相同的大小或相同的表示形式。
具有不同指針類型表示的實現示例是 Cray PVP,其中指針類型的表示對於void *
和char *
為 64 位,但對於其他指針類型為 32 位。
請參閱“Cray C/C++ 參考手冊”,“9.1.2.2”中的表 3.http://docs.cray.com/books/004-2179-003/004-2179-003-manual.pdf
在 C 語言中,所有指針類型的表示形式都可能不同。 所以,是的, int *
與void *
不同。 一個能夠說明這種差異的現實平台可能很難(或不可能)找到,但在概念層面上,差異仍然存在。
換句話說,在一般情況下,不同的指針類型有不同的表示。 int *
與void *
不同,也與double *
不同。 就 C 語言而言,您的平台對void *
和int *
使用相同的表示形式這一事實只不過是巧合。
該語言聲明某些指針類型需要具有相同的表示形式,其中包括void *
與char *
,指向不同結構類型的指針,或者說, int *
和const int *
。 但這些只是一般規則的例外。
其他人已經充分解決了將int *
傳遞給具有固定數量參數的原型函數的情況,該函數需要不同的指針類型。
printf
不是這樣的函數。 它是一個可變參數函數,因此默認參數提升用於其匿名參數(即格式字符串之后的所有內容),如果每個參數的提升類型與格式效應器預期的類型不完全匹配,則行為未定義。 特別是,即使int *
和void *
具有相同的表示,
int a;
printf("%p\n", &a);
有未定義的行為。
這是因為調用框架的布局可能取決於每個參數的確切具體類型。 為指針和非指針類型指定不同參數區域的 ABI 在現實生活中已經出現(例如,摩托羅拉 68000 希望您盡可能將指針保留在地址寄存器中,將非指針保留在數據寄存器中)。 我不知道有任何現實世界的 ABI 隔離了不同的指針類型,但這是允許的,聽到一個我也不會感到驚訝。
p
參數應是指向void
的指針。 指針的值以實現定義的方式轉換為打印字符序列。
實際上,除了古老的大型機/小型機外,不同的指針類型極不可能具有不同的大小。 但是,它們具有不同的類型,並且根據printf
的規范,使用格式說明符的錯誤類型參數調用它會導致未定義的行為。 這意味着不要這樣做。
使用 printf 打印指針值時,調用者必須將指針強制轉換為 void *
對於所有指針,即使強制轉換為void *
也不夠。
C 有兩種指針:指向對象的指針和指向函數的指針。
任何對象指針都可以毫無問題地轉換為void*
:
printf("My pointer is: %p", (void *)my_ptr); // OK when my_ptr points to an object
未定義指向函數的指針到void *
轉換。
考慮 2021 年的系統,其中void *
是 64 位,函數指針是 128 位。
C 確實指定(我的重點)
任何指針類型都可以轉換為整數類型。 除了前面指定的之外,結果是實現定義的。 如果結果不能以整數類型表示,則行為未定義。 結果不必在任何整數類型的值范圍內。 C17dr § 6.3.2.3 6
要打印函數指針可以嘗試:
printf("My function pointer is: %ju", (uintmax_t) my_function_ptr); // Selectively OK
C 缺少真正通用的指針,也缺少打印函數指針的干凈方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.