浮點數類型轉換的及其內存模型
先看一段測試code:
void do_test() { unsigned int uValue = 0xC1480000; printf("uValue = %u,%d,%x,&uValue = %p\n",uValue,uValue,uValue,&uValue); float fValue1 = (float) uValue; printf("fValue1 = %f,&fValue1 = %p, *((unsinged int*)&fValue1) = %x\n",fValue1,&fValue1,*((unsigned int*)&fValue1)); float fValue2 = *((float*) &uValue); printf("fValue2 = %f,&fValue2 = %p, *((unsinged int*)&fValue2) = %x\n",fValue2,&fValue2,*((unsigned int*)&fValue2)); }
它的運行結果為:
uValue = 3242721280,-1052246016,c1480000,&uValue = 0xbe99b59c fValue1 = 3242721280.000000,&fValue1 = 0xbe99b5a0, *((unsinged int*)&fValue1) = 4f414800 fValue2 = -12.500000,&fValue2 = 0xbe99b5a4, *((unsinged int*)&fValue2) = c1480000
首先第一段uValue:
它的16進制表達方式也就是內存裏面的值為0xC1480000;
將數據0xC1480000表示成unsigned int,它的值是3242721280;
將數據0xC1480000表示成int,它的值是-1052246016。
第二段fValue1:
它的值是從uValue強轉而來的;
它的內存裏面的值是0x4F414800,也就是說float fValue1 = (float) uValue;這種強轉會改變內存裏的值;
而這個0x4F414800表示成float,它的值是3242721280.000000。
第三段fValue2:
它的內存值是uValue的內存值拷貝而來的,是0xC1480000
而是0xC1480000表示成float,它的值是-12.5,也就是說float fValue2 = *((float*) &uValue);的賦值方式不會改變內存值。
我們從會變得角度看看上面的幾個賦值過程:
000010e4 <_Z7do_testv>: 10e4: b57f push {r0, r1, r2, r3, r4, r5, r6, lr} 10e6: ab06 add r3, sp, #24 ; 第一段 10e8: 4919 ldr r1, [pc, #100] ; (1150 <_Z7do_testv+0x6c>) 10ea: 481a ldr r0, [pc, #104] ; (1154 <_Z7do_testv+0x70>) 10ec: f843 1d0c str.w r1, [r3, #-12]! 10f0: 460a mov r2, r1 10f2: 9300 str r3, [sp, #0] 10f4: 4478 add r0, pc 10f6: 460b mov r3, r1 10f8: f7ff ec0e blx 918 <[email protected]> ; 第二段 10fc: ed9d 7a03 vldr s14, [sp, #12] 1100: eef8 7a47 vcvt.f32.u32 s15, s14 1104: a806 add r0, sp, #24 1106: ee17 2a90 vmov r2, s15 110a: eef7 0ae7 vcvt.f64.f32 d16, s15 110e: f840 2d08 str.w r2, [r0, #-8]! 1112: edcd 7a01 vstr s15, [sp, #4] 1116: 9000 str r0, [sp, #0] 1118: 480f ldr r0, [pc, #60] ; (1158 <_Z7do_testv+0x74>) 111a: ec53 2b30 vmov r2, r3, d16 111e: 4478 add r0, pc 1120: f7ff ebfa blx 918 <[email protected]> ; 第三段 1124: f8dd c00c ldr.w ip, [sp, #12] 1128: ab06 add r3, sp, #24 112a: 480c ldr r0, [pc, #48] ; (115c <_Z7do_testv+0x78>) 112c: ee00 ca10 vmov s0, ip 1130: f843 cd04 str.w ip, [r3, #-4]! 1134: 4478 add r0, pc 1136: 9300 str r3, [sp, #0] 1138: eeb7 1ac0 vcvt.f64.f32 d1, s0 113c: f8cd c004 str.w ip, [sp, #4] 1140: ec53 2b11 vmov r2, r3, d1 1144: f7ff ebe8 blx 918 <[email protected]> 1148: b007 add sp, #28 114a: f85d fb04 ldr.w pc, [sp], #4 114e: bf00 nop 1150: c1480000 1154: 00000105 1158: 000000fb 115c: 00000122
第二段中的vcvt.f32.u32指令就是u32轉成float的,而vcvt.f64.f32是float轉double的。
那第二段為什麽會出現vcvt.f32.u32呢?因為print中的%f表示的是double類型,所以fValue1就強制轉換成double類型了。
同樣,第三段中,也有vcvt.f64.f32,但第三段不會有vcvt.f32.u32。
因此浮點數的強制類型轉換,會帶來內存值的改變,而這個內存值的改變正是用vcvt指令進行的。
它的轉換依據是IEEE標準,可以參考http://blog.csdn.net/demon__hunter/article/details/3566232
0xC1480000 -> 1100 0001 0100 1000 0000 0000 0000 0000
符號位:1 表示是負數
指數位:100 0001 0 = 130
小數位: 100 1000 0000 0000 0000 0000
運算方法:
小數位前面加個1和點‘.’
1.100 1000 0000 0000 0000 0000
指數位值減去127,如130-127=3,表示小數點右移3個位,得:
1100 .1000 0000 0000 0000 0000
小數點前面的數1100 = 1*(2^3)+1*(2^2)+0*(2^1)+0*(2^0) = 12
小數點後面的數1000 0000 0000 0000 0000 = 1*(2^-1)+0*(2^-2)+0*(2^-3)+... = 1*(2^-1) = 0.5
加上符號位後,它的值就是-12.5
同理:
0x4F414800 -> 0100 1111 0100 0001 0100 1000 0000 0000
符號位:0 表示是正數
指數位:100 1111 0 = 158
小數位: 100 0001 0100 1000 0000 0000
運算方法:
小數位前面加個1和點‘.’
1.100 0001 0100 1000 0000 0000
指數位值減去127,如158-127=31,表示小數點右移31個位,得:
1100 0001 0100 1000 0000 0000 0000 0000.
明顯,這個值就沒有小數點後面的數了,
二進制1100 00001 0100 1000 0000 0000 0000 0000轉換成十進制就是3242721280
浮點數類型轉換的及其內存模型