作者VictorTom (鬼翼&娃娃魚)
看板C_and_CPP
標題Re: [問題] float *r => int
時間Thu Mar 25 01:38:56 2010
※ 引述《bearbabybaby (熊寶寶)》之銘言:
: 在下最近練習指標的時候遇到一個問題...
: #include<stdio.h>
: int main()
: {
: int a=999;
在32 bit little endian的環境上....
某個memory address裡依序存入了:
0x00100000: 0xE7 0x03 0x00 0x00
: short int *p;
: int *q;
: float *r;
: double *s;
: p=(short int*)&a;
p是short ptr, 指到了0x00100000
: q=&a;
q是int ptr, 指到了0x00100000
: r= (float *) &a;
r是float ptr, 指到了0x00100000
: s=(double*)&a;
s是double ptr, 指到了0x00100000
: printf("p=%d\n",*p);
p是short ptr, 所以取值 0xE7 0x03 => 999
Edit1: 照精華區: z->3->7->17裡的介紹....
實際上不足sizeof(int)的參數會push到int alignment
所以實際上可能灌入printf的是 0xE7 0x03 XX XX
由於後兩個 XX 不參與解值也會被skip掉, 所以不影響結果:)
: printf("q=%d\n",*q);
q是int ptr, 所以取值 0xE7 0x03 0x00 0x00 => 999
: printf("r=%s\n",*r);
r是float ptr, 所以取值 0xE7 0x03 0x00 0x00
但是因為是float, 所要要照IEEE 754去解值....
解值結果會得到一個exp全為0的超小數....
而小弟我在VC2005的printf實作裡觀察到的是....
當數值小到一個程度時, 會直接被視為傳入NULL....
所以用%s印, 會印出char string ptr為NULL時的特殊字串<null>
如果今天剛好是大一點的數, 比如直接拿0.0000001灌下去....
內部實作會看到它被解成address: 0xA0000000
於是這樣去印字串自然會存取到不合法的記憶體報RTE....
改用%f去fit float ptr的dereference的話....
印出0.000000是因為值太小超過預設印出的精確位數....
用%.50f去印, 就可以看到它會印出0.00000以後的數值了....
PS. 其實小弟我沒有仔細trace那是怎麼被解析的....
所以0xA0000000與<null>的狀況我推不出怎麼來的....
也不是很肯定各家的實作會不會產生同樣的結束....
: printf("s=%d\n",*s);
s是double ptr, 所以取值 0xE7 0x03 0x00 0x00 ?? ?? ?? ??
實際上去印*s因為high 4 bytes根本不知道是什麼鬼....
所以s的dereference不但會access violation, 結果也是未知....
實務上沒發生AV的理由可能是stack裡access到的還是合法空間....
而且只做讀取沒做寫入, 所以只是不知道會讀出什麼鬼....
但是實際上這是有問題的code, 那又為什麼可以印出999呢??
因為用%d印, 處理valist的地方會只取引數的前4 byte來用....
所以雖然push了0xE7 0x03 0x00 0x00 ?? ?? ?? ??進了stack....
%d印時還是剛好只拿了0xE7 0x03 0x00 0x00 => 999 印了出來....
: return 0;
: }
: 這樣跑出來的結果 p q s 都會是999
: 但是唯讀r會是0
: 有大大可以幫我解釋為什麼嗎?
: 還有~要如何才能顯示出正確的值?
老實說我不曉得你期望什麼才是正確的值, 想要都印999??
本來我預期%s改%d就可以像變數s一樣印出999出來....
不過它實際印出0, 所以不確定上面的描述是否有誤解之處....
只是我試了讓a值為999999999然後印printf("s=%d\n%d\n%d",*s,1);
結果是999999999, -858993460(VC的debug check value 0xCCCCCCCC), 1
所以double那邊推論應該沒錯; 問題是你想要印出什麼東西??
因為老實說你這樣玩弄指標總覺得怪怪的, 不曉得你想要做什麼....
: 感恩~
又, Big Endian的環境, 有的結果或許就會不同了:)
==
以上, 如有謬誤, 還請大大不吝指正; 尤其float的case....<(_ _)>
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 220.132.174.98
※ 編輯: VictorTom 來自: 220.132.174.98 (03/25 01:43)
→ rephansu:他應該是想要全部的format都用%d格式輸出 03/25 10:27
→ VictorTom:這樣問題就在, 下個0.1之類的用%d會印出什麼了說@_@" 03/25 10:45
→ VictorTom:今天才想到的問題, %d印short的話, 是不是應該經過 03/25 10:45
→ VictorTom:integer promotion啊?? 昨天發文忘了注意這一點了Orz 03/25 10:46
→ VictorTom:剛找到精華區: z->3->7->17與18 就有講到了....Orz 03/25 10:55
→ VictorTom:不是int promotion, 而是int alignment, 修一下文好了XD 03/25 10:56
Edit1: 增加一點參照精華區後對short做int alignment的描述....^^||
※ 編輯: VictorTom 來自: 220.134.41.4 (03/25 11:01)
→ rephansu:直接看反組譯碼或許會比較容易釐清XD 03/25 11:05
→ VictorTom:反糸且言睪?_?> 那是什麼, 可以吃嗎@o@> (光速逃XD) 03/25 11:15