簡體   English   中英

C++ 無符號和有符號轉換

[英]C++ unsigned and signed conversion

我以前見過這種問題,但提供的答案並沒有讓我明白一切。 發布此問題時,通常會附上下一個示例:

#include <iostream>

int main()
{
    unsigned int u = 10;
             int i = -42;

    std::cout << i + i << std::endl;
    std::cout << i + u << std::endl;

    return 0;
}

輸出:

-84
4294967264

所有按預期工作 int 轉換為無符號。 但是如果i絕對值小於u則似乎沒有發生這種轉換。

#include <iostream>

int main()
{
    unsigned int u = 10;
             int i = -3;

    std::cout << i + i << std::endl;
    std::cout << i + u << std::endl;

    return 0;
}

輸出:

-6
7

我沒有看到任何提到它的答案,也找不到任何解釋。 盡管這似乎是合乎邏輯的事情發生,但我對此沒有任何解釋。

后:

unsigned int u = 10;
         int i = -3;

i + u的計算首先將i轉換為unsigned int 對於 32 位unsigned int ,此轉換包含模 2 32 ,即 4,294,967,296。 這種包裝的結果是 -3 + 4,294,967,296 = 4,294,967,293。

轉換后,我們將添加 4,294,967,293(轉換后的i )和 10 ( u )。 這將是 4,294,967,303。 由於這超出了 32 位unsigned int ,因此它以 4,294,967,296 為模包裝。 其結果是 4,294,967,303 − 4,294,967,296 = 7。

因此打印“7”。

但是如果 i 的絕對值小於 u,則似乎沒有發生這種轉換。

你的假設是錯誤的:這種轉換正在發生。 “這種轉換”是指當 -3 轉換為無符號類型時,結果是 4'294'967'293。

我沒有看到任何提到它的答案,也找不到任何解釋。

無符號算術是模塊化的。 這就是模算術的工作原理。

要理解模算術,請考慮 12 小時制的工作原理。 它也是模塊化的。 您會注意到鍾面沒有任何負數:

  • 時間是 10 點(今天上午)。 3 小時前,現在幾點了? 那是 7 點(今天上午)。
  • 時間是 10 點(今天上午)。 42 小時前,現在幾點了? 4點(前天下午)

無符號算術的工作原理正是如此。 除了在 32 位類型的情況下有 4'294'967'296 個值而不是 12 個值。


為了將不可表示的值轉換為可表示的范圍,只需添加或減去模數(時鍾情況下為 12,32 位無符號整數情況下為 4'294'967'296),直到該值處於可表示范圍內。

以下是時鍾示例的數學計算:

R ≡ 10 + (-3)          (mod 12)
// -3 = 9  + (12 * -1)
R ≡ 10 + 9             (mod 12) 
R ≡ 19                 (mod 12)
// 19 = 7  + (12 *  1)
R ≡ 7                  (mod 12)

R ≡ 10 + (-42)         (mod 12)
// -42 = 6 + (12 * -4)
R ≡ 10 + 6             (mod 12)
R ≡ 16                 (mod 12)
// 16 = 4 +  (12 *  1)
R ≡ 4                  (mod 12)

以下是您的示例的數學計算:

R ≡ 10 + (-42)         (mod 4'294'967'296)
// -42           = 4'294'967'254 + (4'294'967'296 * -1)
R ≡ 10 + 4'294'967'254 (mod 4'294'967'296)
R ≡ 4'294'967'264      (mod 4'294'967'296)

R ≡ 10 + (-3)          (mod 4'294'967'296)
// -3            = 4'294'967'293 + (4'294'967'296 * -1)
R ≡ 10 + 4'294'967'293 (mod 4'294'967'296)
R ≡ 4'294'967'303      (mod 4'294'967'296)
// 4'294'967'303 = 7             + (4'294'967'296 * -1)
R ≡ 7                  (mod 4'294'967'296)

有兩個概念對於理解負數和無符號之間的關系非常重要。 第一個是Ones的恭維 這是一個非常古老的標准,不再使用,但很容易理解。 負數只是每個位的非。 -1 = ~1 = 1111...1110。 補碼的問題是有兩個零 (+0/-0)。 這很快就會變得復雜。 考慮

X = 2-2 Y = -2+2 X != Y

這就是現代計算機和 C/C++ 采用二進制恭維的原因 二元贊美下降-0(沒有這樣的事情)等等

-1 = 1111...1111 -2 = 1111...1110 so -v = ~1+1

您會看到沒有“操作”可以在有符號和無符號之間進行轉換。 在硬件中,每個都只是一個位向量。 值是有符號還是無符號,只是如何解釋位的問題。 為了證明這一點,你只需嘗試

printf("%x", -1); // print a signed value as if it was unsigned

因此,回到您的問題,任何小的 (+v) 數字都是相同的,無論是否有符號。 (signed) 1 與無符號 (1) 相同。 只有當最高位為 1 時,解釋才會改變。

順便說一句:在 C/C++ 中,“unsigned int”可以縮寫為“unsigned”,這是規則的殘余,即任何未指定的類型都被假定為 int。

暫無
暫無

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

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