作者vvrr (vvrr)
看板C_and_CPP
標題[問題] printf & 型態轉換
時間Mon Feb 15 14:51:38 2016
開發平台(Platform): (Ex: VC++, GCC, Linux, ...)
GCC
問題(Question):
printf的結果會根據型態的不同而改變
餵入的資料(Input):
int a = 5000;
char b = (char)a;
printf("b = %x\n", b);
預期的正確結果(Expected Output):
b = 88 (5000 = 0x1388)
錯誤結果(Wrong Output):
b = ffffff88
補充說明(Supplement):
嘗試了一些a的初始值和結果,有點不太明白為什麼會變成這樣,整理如下:
int a = 5000; --> b = ffffff88
int a = 0x1234; --> b = 34
int a = 50; --> b = 32 // 這個很正常
char a = 50; --> b = 32 // 這個很正常
char a = 0x7F; --> b = 7f
char a = 0x80; --> b = ffffff80
char a = 0x81; --> b = ffffff81
主要是前兩個,為什麼一個會印出ffffff,一個就不會?
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 60.250.31.103
※ 文章網址: https://webptt.com/m.aspx?n=bbs/C_and_CPP/M.1455519100.A.9CF.html
1F:→ longlongint: char的範圍是? 02/15 15:05
2F:→ andrenvq57: 為什麼不是0x000088而是0xffff88 overflow是直接用ff 02/15 15:17
3F:→ andrenvq57: 頂替嗎 02/15 15:17
4F:→ stupid0319: char* b = (char*)&a; 這樣比較理想 02/15 15:20
5F:→ stupid0319: 結果不是b = ffffff88嗎,怎麼下一行又變b = ffffff34 02/15 15:23
※ 編輯: vvrr (60.250.31.103), 02/15/2016 15:37:04
6F:→ vvrr: 是88沒錯@@ 抱歉 02/15 15:37
7F:推 stupid0319: char = 0x7F ,0x80 , 0x81 各試看看吧 02/15 15:42
8F:→ vvrr: char就,一般的char. 應該是-128~127 02/15 15:43
9F:→ vvrr: 2F,我也不知道為什麼是ff,gcc印出來的.. 02/15 15:44
※ 編輯: vvrr (60.250.31.103), 02/15/2016 15:46:25
10F:推 CoNsTaR: 因為你 printf 要求的輸入不是 char 你卻給他 char 吧… 02/15 15:45
11F:推 CoNsTaR: 它需要一個比 char 更大的型態 02/15 15:47
12F:→ CoNsTaR: 像你這裡輸出的結果是 4*8=32bit 的型態 02/15 15:47
13F:→ vvrr: 如果前面都會被補成ffff就還好,但是有些就不會 02/15 15:48
※ 編輯: vvrr (60.250.31.103), 02/15/2016 15:49:09
14F:→ CoNsTaR: int i = 5000; 02/15 15:49
15F:→ CoNsTaR: char c = (char)i;i = c;printf("%p\n", i); 02/15 15:49
16F:→ CoNsTaR: @vvrr因為你不能知道你讀超過b之外的值是多少啊 02/15 15:50
17F:→ CoNsTaR: 如果b前面的變數剛好都是0那讀出來當然就不會有f 反之 02/15 15:52
18F:→ CoNsTaR: 亦然 02/15 15:52
19F:→ CoNsTaR: 這裡沒有 overflow 只有 overbound 02/15 15:53
20F:推 stupid0319: FFFFFF不是補上去的吧......看了我都快吐血了 02/15 16:04
21F:推 stupid0319: 神人來說一下char跟int的負數怎麼表示吧 02/15 16:07
22F:→ stupid0319: char跟int的-1各為FF跟FFFFFFFF 02/15 16:11
23F:→ stupid0319: -2呢,FE跟FFFFFFFE 02/15 16:11
24F:→ stupid0319: 所以char的0x88跟int的0xffffff88是等值的 02/15 16:13
25F:→ stupid0319: 在一些程式中,輸入0x80000000可能造成bug 02/15 16:15
26F:→ stupid0319: 很多遊戲的洗錢BUG就是這麼來的 02/15 16:15
27F:推 LPH66: 關鍵字: sign extension 02/15 16:19
28F:→ besmartAE: (unsigned char)才對 02/15 16:21
29F:→ stupid0319: 一個道具10萬塊錢好了,買21475個,變成0x80003FE0 02/15 16:21
30F:→ stupid0319: 買了道具後系統還要付給你21億 02/15 16:22
31F:→ vvrr: 「所以char的0x88跟int的0xffffff88是等值的」 02/15 16:36
32F:→ vvrr: 所以printf會先把後面的數字轉成int嗎? 02/15 16:36
33F:→ vvrr: ^^^^^^^^^^ 後面的char型態的b 02/15 16:37
34F:推 stupid0319: %x Unsigned hexadecimal integer 02/15 16:40
35F:推 apologize: unsigned char b = (char)a; 改成 02/15 18:21
36F:推 LPH66: >vvrr 16:36 是, 不過不是 printf 轉的 02/15 22:26
37F:→ LPH66: 而是因為 printf 屬於可變參數函式, 不到 int 等級的整數 02/15 22:26
38F:→ LPH66: 規定要轉成 int 再傳進去, 所以在那時就已經轉了 02/15 22:27
39F:→ LPH66: 也因為規定轉成 int, 所以會轉成一個有號整數 02/15 22:27
40F:→ LPH66: 這才用上了我上面講的 sign extension 02/15 22:28
41F:→ LPH66: 概念上就是如 stupid0319 講的, 0x88 (等於十進位 -120) 02/15 22:29
42F:→ LPH66: 會變成 int 的 -120 (0xffffff88) 02/15 22:29
43F:→ LPH66: 那因為二進位觀點來看就是最高位的正負號位元往前補滿 02/15 22:29
44F:→ LPH66: 所以要說「ffffff 是補上去的」技術上來說也沒有錯就是了 02/15 22:30
45F:推 azter: 其實可以開小算盤的程式設計師模式 02/16 01:00
46F:→ azter: 第一步計算5000+128 02/16 01:02
47F:→ azter: 第二步 將第一步結果 mod 256 02/16 01:03
48F:→ azter: 第三步 將第二步的結果再減去減去128 02/16 01:04
49F:→ azter: 小算盤的輸出結果是-120 02/16 01:07
50F:→ azter: 單看-120可能看不出端倪,請看小算盤下面顯示一堆1 0那欄 02/16 01:10
51F:推 LPH66: 要講型態轉換的話, 這樣操作: (1) 左下角選 dword, 10 進位 02/16 03:30
52F:→ LPH66: 然後輸入 5000; (2) 左下角點選 byte; 這等同於轉型成 char 02/16 03:31
53F:→ LPH66: 你會看到它變成了 -120 了 02/16 03:31
54F:→ LPH66: (3) 根據我上面說的, 傳進 printf 前會再轉成 int 02/16 03:31
55F:→ LPH66: 所以再點回 dword, 你會看到數值還是 -120 02/16 03:32
56F:→ LPH66: 但下面的二進位顯示部份前面卻是全部補了 1 進去 02/16 03:32
57F:→ LPH66: (4) 輸出成 %x, 所以點選 16 進位, 就看到 ffffff88 出來了 02/16 03:33
58F:→ LPH66: 你把你實驗的值代換掉上面的 5000, 觀察下面二進位顯示 02/16 03:34
59F:→ LPH66: 就會知道為什麼有些數會這樣變有些數會那樣變 02/16 03:34
60F:→ vvrr: 謝謝大家<(_ _)> 02/16 10:58
61F:→ vvrr: 1. int a 轉成 char b的時候,不論正負只留最後1個byte 02/16 10:59
62F:→ vvrr: 2. char b傳進printf前會根據b此時代表數值轉成signed int 02/16 11:00
63F:→ vvrr: 3. printf實際上印出來的都是int.有些只看到1byte的只是前面 02/16 11:01
64F:→ vvrr: 都是0(而且我沒有叫printf印出來) 大概是這樣沒錯吧 02/16 11:02