看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《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