簡體   English   中英

這是 glibc printf 中的錯誤嗎?

[英]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_tINT16_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM