iT邦幫忙

2026 iThome 鐵人賽

DAY 8
1
自我挑戰組

韌體工程師的不只 0x10 個問題系列 第 8

Day 8 - 隱含類型轉換的陷阱

  • 分享至 

  • xImage
  •  

試分析下列程式碼:

#include <iostream>

int main()
{
    unsigned int a = 6;
    int b = -20;
    (a + b > 6) ? puts(">6") : puts("<=6");

    return 0;
}

這裡有個 unsigned int 的變數 a,值為 6;另外有個 int 變數 b,值為 -20,那兩者相加是否大於 6 呢?

-20 + 6 = -14,而 -14 小於 6,所以在三元運算式中,應該會顯示 <=6 對吧?那實際上顯示的是什麼呢?

>6

為什麼?!

隱含類型轉換 Implicit Type Conversion

這關鍵就在於 6-20 兩者的資料型別:

  • 6unsigned int
  • -20int

6 比較簡單,轉成二進制就是 0110

-20 因為帶有負號,轉二進制就比較複雜了,會用到「二補數(Two's Complement)」,其步驟如下(以 8 位元為例):

  1. 用二進制表示正 200000 0000 0001 0100
  2. 位元全部反轉:1111 1111 1110 1011
  3. 尾巴加 1:1111 1111 1110 1100

這串 1111 1111 1110 1100 在二補數時,最高位元 1 代表負號,因此轉換成十進制時為:

   1       1      1      1      1      1      1     1     1    1    1    0   1   1   0   0
-32768 + 16384 + 8192 + 4096 + 2048 + 1024 + 512 + 256 + 128 + 64 + 32 + 0 + 8 + 4 + 0 + 0 = -20

但當 unsigned intint 相加時,有號數 int 會被默默地轉成無號數 unsigned int,也就是說最高位元 1 不再代表 -32768,而是 +32768

所以同樣是 1111 1111 1110 1100,在十進制中就變成:

  1       1      1      1      1      1      1     1     1    1    1    0   1   1   0   0
32768 + 16384 + 8192 + 4096 + 2048 + 1024 + 512 + 256 + 128 + 64 + 32 + 0 + 8 + 4 + 0 + 0 = 65516

所以 65516(二進制為 1111 1111 1110 1100)跟 6(二進制為 0000 0000 0000 0110)相加後:

  1111 1111 1110 1100 <- 65516 轉十進制
+ 0000 0000 0000 0110 <- 6 轉十進制
----------------------
  1111 1111 1111 0010 <- 十進制為 65522

最終結果為 65522,因此 >6 成立。

為什麼要做隱含類型轉換?

在寫這篇文章時,我不禁好奇為何要有這樣的機制?為什麼是 int 改成 unsigned int,而不是 unsigned int 轉成 int

在 C++ 中,如果有不同資料型別混搭,編譯器會默默把位元數較低者轉為位元數較高者的資料型別,其順序由少位元到多位元如下:

(最少位元)bool -> char -> short -> int -> long -> long long -> float -> double -> long double(最多位元)

讓較少位元者擴展為較多位元者,可讓資料型別對齊時,確保含有較多位元資訊者資料不流失。

然而,intunsigned int 位元數量相同,又是怎麼決定誰轉成誰的呢?

在 C++ 中,兩資料型別範圍如下:

  • int-2,147,483,6482,147,483,647
  • unsigned int04,294,967,295

所以如果有一個數是 3,000,000,000,這個數在 unsigned int 過得很好,但如果硬轉成有號整數 int,會直接超過 int 的容許範圍、直接爆掉;反之,任何在 int 範圍中的數,在轉為 unsigned int 後,都還是能穩穩地保持在 unsigned int 的容許範圍。

參考資料

  1. Implicit Type Conversion in C with Examples (GeeksforGeeks)
  2. Type Conversion in C++ (GeeksforGeeks)
  3. 韌體工程師的0x10個問題

上一篇
Day 7 - 神奇的「最大匹配原則」與前後置遞增
下一篇
Day 9-萬惡的指標
系列文
韌體工程師的不只 0x10 個問題19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言