看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《zebraseven (Die walkuere)》之銘言: : 開發平台(Platform): (Ex: VC++, GCC, Linux, ...) : Windows NT : 問題(Question): : 如果在一個程式裡 : 只打上一行printf("%d %d", 4*atan(1), sin(4*atan(1))); : 我的執行結果會很奇怪,如下: : 1413754136 1074340347 : 但是如果把第一個 %d 改成了 %g : printf("%g %d", 4*atan(1), sin(4*atan(1))); : 答案竟然變成了我想要的 : 3.14159 0 : 第一個答案怎樣我不管, : 我的問題是第二個,它的輸出型態都是 %d : 但為什麼第一次跟第二次的執行結果不一樣呢?? : 特別說一下,我沒有宣告任何的暫存變數, : 程式碼就僅僅只有這兩行和標頭檔而已... : 這問題實在讓在下百思不得其解... : 有勞板上的大大們解惑!! 首先,要知道 4*atan(1) 這個結果是怎麼存在電腦記憶體裡面的 寫成二進位的話,它實際上是長這個樣子: 0100000000001001001000011111101101010100010001000010110100011000 約 3.14159 如果不知道為什麼,請找IEEE 754 0100000000001001001000011111101101010100010001000010110100011000 這一長串數字,如果從中間切成兩組32bit的數字: 01000000000010010010000111111011 = 1074340347 01010100010001000010110100011000 = 1413754136 有沒有覺得很眼熟?那就是你一開始印出來的東西了 printf("%d %d", 4*atan(1), sin(4*atan(1))); 這行的動作是這樣的: (1) printf 第一次看到 %d, 它知道 %d 代表該印出 32 位元的整數 因此它從記憶體裡面拿出32元位長度的資料,並且印出來 這個時候拿到的是3.14159這個數字的後半段,1413754136 (2) printf 第二次看到 %d, 它知道 %d 代表該印出 32 位元的整數 因此它從記憶體裡面拿出32元位長度的資料,並且印出來 這個時候拿到的是3.14159這個數字的前半段,1074340347 (3) 兩個%d都印完了,任務結束,sin(4*atan(1))的結果被無視了 printf("%g %d", 4*atan(1), sin(4*atan(1))); 在我電腦上的執行結果是 3.14159 856972295,而不是你所說的 3.14159 0 改成這樣之後,就變成了 (1) printf 第一次看到 %g, 它知道 %g 代表該印出 64 位元的浮點數 因此它從記憶體裡面拿出64元位長度的資料,並且印出來 這個時候拿到的是完整的3.14159這個數字 (2) printf 第二次看到 %d, 它知道 %d 代表該印出 32 位元的整數 因此它從記憶體裡面拿出32元位長度的資料,並且印出來 這個時候拿到的是sin(4*atan(1))的後半的結果 856972295 (3) 兩個%g, %d都印完了,任務結束,sin(4*atan(1))另一半被無視 這就是為什麼您只是把第一個 %d 改成 %g 印出來的結果會導致第二個數不同 printf根據您所輸入的 %d 或 %g 決定從記憶體剩下的資料裡拿出多少出來印 至於為什麼在您的電腦上,可以跑出 0 這個數 這就是其他板友講的「未定義行為」了 根據不同的電腦、不同的printf實作 可能印出「856972295」或者「0」或者其他什麼莫名其妙的東西,都很正常 您可以把 sin(4*atan(1)) 換成別的東西,結果應該就不是那麼正確了 ---- 其實這篇文章是用結果去推斷過程的,畢竟我懶得挖printf原始碼XD 坦白說我不知道自己講的夠不夠正確,不過意思應該有點接近了 接下來就交給t大繼續補充 (傳棒子) -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.35.184.77 ※ 編輯: james732 來自: 114.35.184.77 (11/07 13:53)
x000032001:推 11/07 14:07
CPofChina:PUSH 11/07 14:16
chchwy:好清楚 11/07 14:19
angleevil:超哥是個人才 11/07 14:30
LPH66:推 我前面推文說的要很大一篇就是這一篇... 11/07 14:30
其實我已經省略了很多我自己都搞不懂的細節...XD
LPH66:另外我沒記錯的話 傳的參數在記憶體的位置是實作規定 11/07 14:33
LPH66:沒有一定要在隔壁 只是大部份情形下都會是就是了... 11/07 14:33
johnhmj:我也認同超哥是個人才(發一張人才卡給超哥)(∩_∩) 11/07 15:09
如果是正妹的話,可以喔 (啥)
angleevil:上次有一個正妹被超哥兇跑了.所以此時這沒正妹 11/07 15:15
james732:.....有這回事? 11/07 15:16
angleevil:正妹都找人代寫作業.別找了.超哥 11/07 15:26
james732:說的也是 (嘆) 11/07 15:30
xatier:超哥給個推,另外,(拍拍) 11/07 16:23
purincess:%g跟%lg有差嗎~~? 11/07 16:51
cutecpu:lg 是日立唷XD 11/07 17:06
purincess:日立是LG O___O? 11/07 17:20
purpose:兩家公司合資的 11/07 17:27
purincess:所以下次要印%lg可以印%hitachi嗎 ! (....我去反省) 11/07 18:40
zebraseven:超哥超強 !!! 真的受教了... 這些都GOOGLE不到的呢 !! 11/07 19:15
zebraseven:您真是程設板的樑柱 ~ :)) 11/07 19:15
james732:這麼講太誇張了,板上的高手這麼多,會害他們笑出來 XD 11/07 19:22
purpose:↖才德兼備 11/07 19:36
angleevil:↖才德兼備 11/07 19:42
.........
tropical72:大推超哥!!其實該說的都說完了,要查754,online 就可查. 11/07 20:28
tropical72:另 %g,%lg 在printf並無差別,只在scanf才有差別. 11/07 20:28
tropical72:其實亂碼在特定compiler常看到的可能就那幾個數字,如.. 11/07 20:30
tropical72:0xCCCCCCCC , 寫到後來看到莫名奇妙的都知道有鬼。 11/07 20:31
0xCCCCCCCC 這個東西寫VC就會覺得超親切的啊...XD
tropical72:我補一下好了,上一篇 littleshan 曾提到這行為是 u.b. 11/07 21:22
tropical72:原因是在於printf抓變數出來時,通常還會考慮 padding 11/07 21:22
tropical72:問題,而 padding 實作更不用多說,各家不盡相同。 11/07 21:23
angleevil:padding??? 11/07 21:34
VictorTom:0xcc或0xcd印象中是VC debug build時用來檢查未使用變數 11/07 23:50
VictorTom:或其他輔助除錯功能用的樣子....@_@" 11/07 23:51
lc85301:太強啦~ 11/08 01:10
purincess:%g跟%lg在printf沒差的話 我寫%g (看原文意思是會找64bi 11/08 01:13
purincess:t參數)但是傳float 實際上printf會怎麼做啊~因為看起來 11/08 01:13
purincess:沒有出錯的樣子呢 @@" 11/08 01:13
yayarice:要看堆疊的後面是甚麼吧 結果應該是不可預期的? 11/08 01:46
tropical72:@purincess:這問題和 %lf / %f 在 printf 會怎做是一樣 11/08 02:11
tropical72:但確實 %g / %lg, %f / %lf 在 printf 裡面是不分的。 11/08 02:11
tropical72:有興趣的話直接去 google printf.c 比較快。 11/08 02:12
purincess:好~謝謝!! 11/08 02:24
akasan:c 裡面有規定可變長度參數中float 會promote 成double 11/08 11:09
akasan:更多有關 varargs 的常見問題 11/08 11:09
LPH66:我現在的暱稱就是 0xCCCCCCCC XD 11/08 13:54
LPH66:之所以會選這個值我猜是 0xCC 是 x86 asm 的 int 3 的原因 11/08 13:55
akasan:write solid code ch3 有提到塞0xcc的兩個主要原因int 3 是 11/08 15:32
akasan:其中一個 另一個是值夠大夠奇怪:D 11/08 15:33
LPH66:夠大夠奇怪的值會讓我想到死牛肉(0xDEADBEEF) XD 11/08 15:37
akasan:http://en.wikipedia.org/wiki/Hexspeak 幫補上列表 ㄎㄎ 11/08 15:47
tropical72:真沒想到cc也是個學問,推VictorTom,LPH66,akasan. 11/08 16:25
真的長知識了,原來 0xCC 也是有典故的 ※ 編輯: james732 來自: 140.117.171.40 (11/09 08:55)
angleevil:我比較好奇死牛肉的由來 11/09 09:04
angleevil:Hexspeak(16進制魔術數字)<-- 11/09 09:19
xatier:Linux system call 的 0xFEE1DEAD 超經典 lol 11/09 09:49
iammacross:推~ 05/20 13:27