簡體   English   中英

無符號和有符號的int和printf

[英]Unsigned and Signed int and printf

據我所知,我為signed int分配的值大於它能處理的值。 此外,我應該使用%d表示簽名, %u表示未簽名。 同樣,我不應該將-ve-ve unsigned。 但是如果我進行這樣的分配並使用如下的printf,我會得到如下結果。

我的理解是,在每種情況下,轉換為其兩個恭維二進制表示的數量對於-14294967295是相同的。 這就是為什么%u簽名打印4294967295忽略-ve leftmost bit。 當%d用於signed int時,它使用最左邊的位作為-ve標志並打印-1 類似地, %u表示無符號打印無符號值,但%d導致它將數字視為有符號,因此打印-1 那是對的嗎?

signed int si = 4294967295;
unsigned int  ui = 4294967295;

printf("si = u=%u d=%d\n", si, si);
printf("ui = u=%u d=%d\n", ui, ui);

輸出:

si = u=4294967295 d=-1
ui = u=4294967295 d=-1

signed int si = -1;
unsigned int  ui = -1;

printf("si = u=%u d=%d\n", si, si);
printf("ui = u=%u d=%d\n", ui, ui);

輸出:

si = u=4294967295 d=-1
ui = u=4294967295 d=-1

這就是為什么%u簽名打印4294967295忽略-ve leftmost bit。 當%d用於signed int時,它使用最左邊的位作為-ve標志並打印-1。

在無符號的情況下,“最左邊”或最高有效位不被忽略,並且不是負數; 相反,它的地方價值為2 31

在否定的情況下,符號位不是標志; 相反,它的位置值為-2 31

在這兩種情況下,整數的值等於設置為1的所有二進制數字(位)的位置值的總和。

以這種方式對帶符號值進行編碼稱為二進制補碼 它不是唯一可能的編碼; 你所描述的被稱為符號和數量 ,例如, 一個補充是另一種可能性。 然而,這些替代編碼在實踐中很少遇到,尤其是因為兩個補碼是算術如何在現代硬件上工作,但可能是最神秘的架構。

這里有一些事情讓我們開始說,使用不正確的printf格式說明符是未定義的行為,這意味着程序的結果是不可預測的,實際發生的將取決於許多因素,包括編譯器,體系結構,優化級別等等......

對於由相應標准定義的有符號/無符號轉換,C和C ++都使其實現定義的行為,以轉換大於存儲在有符號整數類型中的值,來自C ++草案標准:

如果目標類型已簽名,則如果可以在目標類型(和位字段寬度)中表示該值,則該值不會更改; 否則,該值是實現定義的。

例如, gcc選擇使用與unsigned相同的約定

為了轉換為寬度N的類型,該值以2 ^ N的模數減少到該類型的范圍內; 沒有信號被提出。

在C和C ++中將-1分配給無符號值時,結果將始終是該類型的最大無符號值,來自草案C ++標准:

如果目標類型是無符號的,則結果值是與源整數一致的最小無符號整數(模2n,其中n是用於表示無符號類型的位數)。 [注意:在二進制補碼表示中,此轉換是概念性的,並且位模式沒有變化(如果沒有截斷)。 - 尾注]

C99的措辭更容易理解:

否則,如果新類型是無符號的,則通過重復地添加或減去一個可以在新類型中表示的最大值來轉換該值,直到該值在新類型的范圍內。

所以我們有以下幾點:

-1 + (UNSIGNED_MAX + 1)

結果是UNSIGNED_MAX

至於printf和不正確的格式說明符,我們可以看到草案C99標准部分7.19.6.1 fprintf函數說:

如果轉換規范無效,則行為未定義.248)如果任何參數不是相應轉換規范的正確類型,則行為未定義。

fprintf包含關於格式說明符的printf ,C ++相對於printf在C中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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