chinese:
c++整數與浮點數的儲存方式
1、整數型別
無符號整數的所有位都用來表示數值,有符號整數的最高位是符號位,其餘位以補碼格式儲存。補碼規則就是用0減去這個數的絕對值(取反加一)。首先我們知道x+x(反碼)=0xffffffff, 因此x+x(反碼)+1=0, 因此x(補碼)=0-x=x(反碼)+1。補碼的好處就是方便計算機做加法。
2、浮點數型別
c++中的浮點數型別分為float和double,float佔4個位元組、double佔8個位元組。浮點數的操作不會用到通用暫存器,而是使用浮點協處理器的浮點暫存器。
浮點數的編碼方式採用的是ieee規定的編碼標準,float和double兩種型別的資料的轉換原理相同,不同的只是表示範圍。ieee規定的浮點數編碼會將乙個浮點數轉換成二進位制數。以科學計數法劃分,將浮點數拆分為3個部分:符號、指數、尾數。
float佔4個位元組,最高位是符號位,緊接著的8位表示指數,其餘位表示尾數。
例項分析:
(1) 12.25f 轉換成二進位制是1100.01,1100.01 = 1.10001 * 2 ^ 3。由於在二進位制中,尾數的最高位始終是1,所以忽略不計。因此尾數字是1000100000...剩下添0。指數部分有乙個規定,由於指數可能出現負數,十進位制的127表示為二進位制為01111111。ieee編碼方式規定,當指數域小於01111111時為乙個負數,反之為正數。因此01111111為0,所以指數字為3+127=130,二進位制為10000010。
符號位:0;指數字:10000010;尾數字:10000100000000000000000;表示成16進製為0x41440000
(2) -0.125f轉換成二進位制是-0.001,由於是負數所以符號位是1, 0.001=1.0 * 2 ^ -3,尾數最高位始終為1,所以忽略不計。尾數字是00000....,指數字是-3+127=124,二進位制是1111100。
符號位:1;指數字:01111100;尾數字:00000000000000000000000;表示成16進製為0xbe000000
(3)1.3f轉換成二進位制的時候,由於0.3轉換成二進位制會得到乙個無窮值: 0.3=0.25+0.03175+....,所以尾數字會捨棄多餘的部分。轉換成二進位制就約等於1.01001100110011001100110,到第23位終止。指數字為0+127,二進位制為01111111
符號位:0;指數字:01111111;尾數字:01001100110011001100110;表示成16進製為0x3fa66666
所以我們得出ieee編碼轉換後,得到的是乙個近似值,存在一定的誤差。所以這也就解釋了為何在c++判斷浮點數值是否為0時,要做乙個區間比較而不是直接進行等值比較。
float3、double型別的ieee編碼fnum;
float fscope = 0.0001f
;if (fnum >= -fscope && fnum <=fscope)
double型別和float型別大同小異,只是double型別表示的範圍更大,精度更高。最高位是符號位,指數字佔11位,尾數字佔42位。double擴大了精度,因此指數字需要加上1023,這些都可以推斷出來,這裡便不再贅述。
4、浮點數指令
浮點數的操作指令和普通資料型別不同,浮點數操作是通過浮點暫存器實現的,而普通資料型別是通過通用暫存器,它們使用的是兩套不同的指令。
浮點暫存器是通過棧結構來實現的,由st(0)~st(7)一共8個棧空間組成,每個浮點暫存器佔8個位元組。每次使用浮點暫存器都是率先壓入st(0),不能越過st(0)直接使用st(1),當8個暫存器都有資料時,此時再壓入資料的時候,st(7)的值會被丟棄。
整型資料與浮點型資料之間的相互轉換,來看一下反彙編出來的指令。
// c++ code:浮點數雖然佔4個位元組,但都是以8個位元組的方式進行處理。當浮點數作為引數時,不能直接壓棧。push指令只能傳入4位元組的資料到棧中,這樣會丟失4位元組的資料。所以使用printf以整數方式輸出浮點數時會產生錯誤。float fnum = (float)argc;;
將位址ebp+8處的整型資料轉換成浮點型,並放入st(0)中,對應變數argc
fild dword ptr [ebp+8];
從st(0)中取出資料以浮點編碼方式存入位址ebp-4中,對應變數fnum
fst dword ptr [ebp-4
]// c++
code:
printf("%f
", fnum);
;這裡對esp執行減8操作是由於浮點數作為變參函式的引數時需要轉換為雙精度浮點值
;這步操作是提前準備8位元組的棧空間,以便存放double資料
sub esp,8
;將st(0)中的資料傳入esp中,並彈出st(0)
fstp
qword ptr [esp]
;以下為printf函式呼叫,略
push offset string "
%f" (0042302c
)call printf (0040e940
)add
esp, 0ch
// c++
code:
argc = (
int)fnum;
;將位址ebp-4處的資料以浮點型壓入st(0)中
fld dword ptr [ebp-4];
呼叫函式__ftol進行浮點數轉換
call __ftol (0040e688);
轉換後結果放入eax,並傳遞到ebp+8位址處
mov dword ptr[ [ebp+8
], eax
// c++
code:
printf("%d
", argc);
;略。。。
浮點數作為返回值的彙編指令:
// c++ code:fnum = getfloat();;
呼叫函式getfloat
call @ilt+5 (getfloat) (0040100a);
由於浮點數需要特殊處理,浮點數佔8位元組,無法使用eax進行傳遞
;使用浮點暫存器st(0)作為返回值
fst dword ptr [ebp-4
]// c++
code:
float getfloat()
;將浮點數儲存在st(0)中,在返回值為浮點數的情況下,無法使用eax
;使用st(0)作為返回值進行傳遞
fld dword ptr [__real@4@4002c400000000000000 (0042301c
)]ret
C 反彙編學習筆記(二)
chinese 1 位址 指標 引用 c 中位址標號用16進製表示,取乙個變數位址使用 操作符,只有變數才存在記憶體位址,常量沒有位址 不包括const定義的偽常量 指標是一種資料型別,用於儲存各種資料型別在記憶體中的位址。指標變數也可以取出位址,所以會出現多級指標。c 中引用不可以單獨定義,定義的...
學習筆記 2011 07 03 反彙編
include using namespace std int main 00c514e6 jmp main 27h 0c514a7h int a 0 00c514e8 mov dword ptr a 0 return 0 00c514ef xor eax,eax 00c514f1 pop edi ...
IDA反彙編學習(一)
toc c語言 if a b 彙編 mov eax,a cmp eax,b a b?jne l1 否 跳過後續指令 mov x,1 是,x,y 賦值 mov y,2 l1 對於迴圈語句,其實也是一樣的,也是通過跳轉指令來實現。c語言 while val1 val2 彙編 mov eax,val1 把...