[問題] printf & 型態轉換

作者: vvrr (vvrr)   2016-02-15 14:51:38
開發平台(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;
作者: longlongint (華哥爾)   2016-02-15 15:05:00
char的範圍是?
作者: andrenvq57 (喂!威,喂?)   2016-02-15 15:17:00
為什麼不是0x000088而是0xffff88 overflow是直接用ff頂替嗎
作者: stupid0319 (徵女友)   2016-02-15 15:20:00
char* b = (char*)&a; 這樣比較理想結果不是b = ffffff88嗎,怎麼下一行又變b = ffffff34
作者: vvrr (vvrr)   2016-02-15 15:37:00
是88沒錯@@ 抱歉
作者: stupid0319 (徵女友)   2016-02-15 15:42:00
char = 0x7F ,0x80 , 0x81 各試看看吧
作者: vvrr (vvrr)   2016-02-15 15:43:00
char就,一般的char. 應該是-128~1272F,我也不知道為什麼是ff,gcc印出來的..
作者: CoNsTaR ((const *))   2016-02-15 15:45:00
因為你 printf 要求的輸入不是 char 你卻給他 char 吧…它需要一個比 char 更大的型態像你這裡輸出的結果是 4*8=32bit 的型態
作者: vvrr (vvrr)   2016-02-15 15:48:00
如果前面都會被補成ffff就還好,但是有些就不會
作者: CoNsTaR ((const *))   2016-02-15 15:49:00
int i = 5000;char c = (char)i;i = c;printf("%p\n", i);@vvrr因為你不能知道你讀超過b之外的值是多少啊如果b前面的變數剛好都是0那讀出來當然就不會有f 反之亦然這裡沒有 overflow 只有 overbound
作者: stupid0319 (徵女友)   2016-02-15 16:04:00
FFFFFF不是補上去的吧......看了我都快吐血了神人來說一下char跟int的負數怎麼表示吧char跟int的-1各為FF跟FFFFFFFF-2呢,FE跟FFFFFFFE所以char的0x88跟int的0xffffff88是等值的在一些程式中,輸入0x80000000可能造成bug很多遊戲的洗錢BUG就是這麼來的
作者: LPH66 (-6.2598534e+18f)   2016-02-15 16:19:00
關鍵字: sign extension
作者: besmartAE (*無敵海灘男孩*)   2016-02-15 16:21:00
(unsigned char)才對
作者: stupid0319 (徵女友)   2016-02-15 16:21:00
一個道具10萬塊錢好了,買21475個,變成0x80003FE0買了道具後系統還要付給你21億
作者: vvrr (vvrr)   2016-02-15 16:36:00
「所以char的0x88跟int的0xffffff88是等值的」所以printf會先把後面的數字轉成int嗎?^^^^^^^^^^ 後面的char型態的b
作者: stupid0319 (徵女友)   2016-02-15 16:40:00
%x Unsigned hexadecimal integer
作者: apologize (人生在世很愜意)   2016-02-15 18:21:00
unsigned char b = (char)a; 改成
作者: LPH66 (-6.2598534e+18f)   2016-02-15 22:26:00
>vvrr 16:36 是, 不過不是 printf 轉的而是因為 printf 屬於可變參數函式, 不到 int 等級的整數規定要轉成 int 再傳進去, 所以在那時就已經轉了也因為規定轉成 int, 所以會轉成一個有號整數這才用上了我上面講的 sign extension概念上就是如 stupid0319 講的, 0x88 (等於十進位 -120)會變成 int 的 -120 (0xffffff88)那因為二進位觀點來看就是最高位的正負號位元往前補滿所以要說「ffffff 是補上去的」技術上來說也沒有錯就是了
作者: azter (Yilin)   2016-02-16 01:00:00
其實可以開小算盤的程式設計師模式第一步計算5000+128第二步 將第一步結果 mod 256第三步 將第二步的結果再減去減去128小算盤的輸出結果是-120單看-120可能看不出端倪,請看小算盤下面顯示一堆1 0那欄
作者: LPH66 (-6.2598534e+18f)   2016-02-16 03:30:00
要講型態轉換的話, 這樣操作: (1) 左下角選 dword, 10 進位然後輸入 5000; (2) 左下角點選 byte; 這等同於轉型成 char你會看到它變成了 -120 了(3) 根據我上面說的, 傳進 printf 前會再轉成 int所以再點回 dword, 你會看到數值還是 -120但下面的二進位顯示部份前面卻是全部補了 1 進去(4) 輸出成 %x, 所以點選 16 進位, 就看到 ffffff88 出來了你把你實驗的值代換掉上面的 5000, 觀察下面二進位顯示就會知道為什麼有些數會這樣變有些數會那樣變
作者: vvrr (vvrr)   2016-02-16 10:58:00
謝謝大家<(_ _)>1. int a 轉成 char b的時候,不論正負只留最後1個byte2. char b傳進printf前會根據b此時代表數值轉成signed int3. printf實際上印出來的都是int.有些只看到1byte的只是前面都是0(而且我沒有叫printf印出來) 大概是這樣沒錯吧

Links booklink

Contact Us: admin [ a t ] ucptt.com