![](/img/trans.png)
[英]Is this incorrect using of popen(), printf and stdout or bug in glibc?
[英]Is this a bug in glibc printf?
使用 glibc 中的stdint.h
(gcc SUSE Linux 版本 9.2.1,Intel Core I7 處理器)我在直接打印INT32_MIN
時遇到了一個最奇怪的行為:
#include <stdio.h>
#include <stdint.h>
void main(void)
{
printf("%d\n", INT16_MIN);
int a = INT16_MIN;
printf("%d\n", a);
printf("%ld\n", INT32_MIN);
long b = INT32_MIN;
printf("%ld\n", b);
printf("%ld\n", INT64_MIN);
long c = INT64_MIN;
printf("%ld\n", c);
}
輸出:
-32768
-32768
2147483648
-2147483648
-9223372036854775808
-9223372036854775808
此外,如果我嘗試
printf("%ld\n", -INT32_MIN);
我得到了相同的結果,但有編譯器warning: integer overflow in expression '-2147483648' of type 'int' results in '-2147483648' [-Woverflow]
。
並不是說這對任何現有程序都非常糟糕,實際上它看起來非常無害,但這是舊 printf 中的錯誤嗎?
這是 glibc printf 中的錯誤嗎?
不。
printf("%ld\n", INT32_MIN);
…2147483648
有一種簡單的方法可以做到這一點。 function 的第二個整數/指針參數應在 64 位寄存器 RCX 中傳遞。 INT32_MIN
是位模式為 0x80000000 的 32 位int
,因為這是 -2,147,483,648 的二進制補碼模式。 在 64 位寄存器中傳遞 32 位值的規則是低 32 位傳遞,調用者不使用高位。 對於這個調用,0x80000000 被放入了低 32 位,而高位恰好設置為零。
然后printf
檢查格式字符串並期望 64 位long
。 所以它在 RCX 中尋找 64 位 integer。 當然,傳遞一個64位的integer的規則是使用整個寄存器,所以printf
取所有64位,0x0000000080000000。 那是 +2,147,483,468 的位模式,因此printf
打印2147483648
。
當然,C 標准沒有定義行為,因此可能會發生其他事情,但這可能是您觀察到的實例中發生的情況。
printf("%d\n", INT16_MIN);
…-32768
由於int
在您的 C 實現中是 32 位的,因此在 function 調用中, int16_t
值INT16_MIN
會自動提升為int
,因此它傳遞了一個int
,並且%d
期望一個正確的值int
,因此不會打印不匹配的值。
同樣,問題中的其他printf
調用具有與轉換規范匹配的 arguments (鑒於int16_t
的特定定義等在您的 C 實現中,它們的值可能與其他實現不匹配)。
讓我們觀察這個特定的片段
long a = INT32_MIN;
printf("%ld\n", a); // #1
printf("%ld\n", INT32_MIN); // #2
它打印以下內容(根據您的示例,我自己沒有嘗試過,它取決於實現,稍后我會注意到):
-2147483648
2147483648
現在,在 #1 中,我們將long
傳遞給printf
。 function 接受void*
並根據指定的格式,我們的void*
指向的值將被解釋為帶signed long
,因此我們最終得到值-2147483648
。
對於#2,我們的情況有些不同。 如果您查看INT32_MIN
的定義方式,您會發現它是一個普通的舊 C 宏,例如:
# define INT32_MIN (-2147483647-1)
所以,我們的線
printf("%ld\n", INT32_MIN);
實際上是
printf("%ld\n", (-2147483647-1));
參數類型不是很長,而是 integer (詳情請參閱此)! 比較一下這個
int b = INT32_MIN;
printf("%ld\n", b);
它會打印出您觀察到的相同值(正值)。
現在歸結為您的問題實際上應該是什么:
當
printf
接收到不在格式說明符中的類型的值時會發生什么?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.