程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言入門篇-03

C語言入門篇-03

編輯:關於C語言

不知不覺已經寫到第三篇了,我們先來回顧一下在02中主要分析了哪些知識點,我們介紹了程序的組成結構PE結構,在這裡再擴展一下大家的知識面,在LINUX平台下,也有類似PE結構的文件格式,也是對COFF的擴展,叫ELF,有興趣的可以研究一下。還介紹了我們的HELLO WORLD一運行起來,操作系統就會為它分配內存,映射地址空間,邏輯地址空間中主要是四個區域,棧(國人一般喜歡稱其為堆棧)、堆、代碼區、數據區。而且我們也分析出了VC6中這幾個區域的大概范圍,也算是讓大家對程序有一種簡單的認識吧。


今天我想了一下,我們主要討論一下01中的問題,01中我們主要討論了整數( [unsigned] (char ,short,int) ) 在內存中的表示形式,今天我們再來做一個練習,然後把方向指向浮點數,並分析浮點數在內存中的表示形式,以及為什麼浮點數的表示會有精度損失問題,這些問題本身並不重要,重要的是理解過程。


復習:隨便給定兩個int型整數,51245412和-6231541 寫出其內存表示形式,假設起始地址為 0X0012FF7C


1、計算51245412的二進制表示形式,不夠32位的話,左邊補0(你懂的),這一步可以用計算器哦

512454120000 0011 0000 1101 1111 0001 0110 0100

然後就是寫出其對應的十六進制了

0000 0011 0000 1101 1111 0001 0110 0100 0 3 0 D F 1 6 4

我們可以得到 它的十六進制表示形式:03 0D F1 64,然後按照高高低低的原則寫入地址中

內存地址數值0X0012FF7C640X0012FF7DF10X0012FF7E0D0X0012FF7F03

看實際的效果


152600704.jpg


注意,我們沒有按F9進行下斷點,取而代之的是嵌入了一段匯編代碼,int 3; 其實就是一個軟中斷,CPU執行到這裡自己就會斷下來,跟我們用F9是一個道理,寫這個東西出來主要是為了讓大家見多識廣嘛,呵呵。我們可以看到圖中黑色選中部分與我們自己計算的一模一樣。


2、 -6231541 這個數不再是正數,而是一個負數,我們要先計算其對應正數的二進制形式,然後按位取反再加1,才能求得最終結果

62315410000 0000 0101 1111 0001 0101 1111 0101

按位取反

0000 0000 0101 1111 0001 0101 1111 01011111 1111 1010 0000 1110 1010 0000 1010

再加1結果是

1111 1111 1010 0000 1110 1010 0000 1011

寫成十六進制

1111 1111 1010 0000 1110 1010 0000 1011 F F A 0 E A 0 B

FF A0 EA 0B 就是我們的結果了


內存地址數值0X0012FF7C0B0X0012FF7DEA0X0012FF7EA00X0012FF7FFF

看實際結果


152631868.jpg


這下我們就又復習了一次補碼,下面我們來研究一下浮點數的表示吧。


其實浮點數也是可以表示二進制的,這是必須滴嘛。。哈哈,如0.5 表示成二進制是 0.1


小數點前的1表示2^n,如 11.01 左起第1個1表示 1*2^1 ,左起第2個1表示1*2^0,最右邊的1表示1*2^(-2) ,其和就是2+1+0.25 = 3.25,這應該不是很難理解吧。現在舉一個例子,我們有一個整數19.375,我們要將它轉換二進制,先轉左邊的整數部分,16+2+1 = 19 ,所以是 10011,那麼右邊的怎麼轉呢,如果大家有基礎的話,都知道除2和乘2方法吧,我們就不去介紹那些方法了,如果你數學學的好,0.375你應該知道是多少,對是3/8 化簡它,3/8=1/8+2/8 =1/8+1/4=2^(-3 ) + 2^(-2) ,明白了吧,我舉0.375是有我的用意的,,哈哈,你被忽悠了。所以這個完整的二進制表示 應該是 10011.011 ,如果你看不懂這裡,那你得好好看看小學數學了哦。我們已經有了二進制了,那麼我們第一步要做的事情就是將它轉換成1.xxxx*2^y 形式,就像 15.62 = 1.562*10^1 ,15642.125 = 1.5642125*10^4 這樣子哦,只不過用的是二進制形式啦,如上面的結果我們就可以將它換算成 1.0011011 * 2^4 , 這個結果其實還是 19.375,只不過是 帶指數的二進制表示形式了。


現在我們已經有了等價於 19.375 的 另一種表示形式 1.0011011 * 2^4 ,而我們說浮點數的內存表示形式也是從這裡開始的,浮點數表示采用的方式不是補碼了,而是移碼。規定

最高位 符號位,為1表示為負數,為0表示為正數

最高位右邊的8位 指數位,左加右減

其它23位 數值位

上表描述的是float類型的數據的表示,符號位好確定,如上,我們的19.375是正數,所以浮號位為0,那麼指數位是怎麼確定的呢?它是以127為根基,我們在將二進制轉成換1.xxxx*2^y 時 ,將小數點進行了移位,移動了y位,如果是左移就用127+y 就是指數位的值,如果是右移,則用127-y的值,就得到指數位,由於我們是進行了左移,所以指數位為127+4 = 131 ,二進制形式為 10000011 ,這樣我們就確定了前九個位,最後23位表示數值就是我們小數點右邊的位0011011,您會說,不夠23位呀,這還不簡單嘛,在右邊補0呀,小數在右邊補0 是不更改原數大小的嘛。。結合一下就是下表

符號位指數位數值位0100000110011011 0000 0000 0000 0000

好了,我們將它們連起來,組合成16進制數據,就像前面做整數的時候一樣

0100 0001 1001 1011 0000 0000 0000 0000 4 1 9 B 0 0 0 0

整合一下數據: 41 9B 00 00 寫入內存空間

內存地址數值0X0012FF7C000X0012FF7D000X0012FF7E9B0X0012FF7F41

驗證奇跡的時刻到了


152701842.jpg


很神奇吧


如果換成負數,大家能不能把它的值直接寫出來呢,就根據上面的數值,其實很簡單了吧,我們是不是只需要將最高位置1即可,那麼原來是4的地方現在值應該為1100,也就是C了吧,再次驗證奇跡


152726562.jpg


是不是很EASY呢。


那麼如果上面的例子你已經理解了,對於double型數據,只有幾個地方需要改動一下就行了,double占8B,64b,還是最高位1位,指數位不是8b了,而是11位,而且基數127也不是127( 2^(8-1) -1 )了,而是1023( 2^(11-1) -1 ),剩余52b為數值位。希望大家可以自己舉幾個例子多做做測試。


好了,基礎介紹就介紹這麼多,問題是我們還有一個問題沒有解決,那就是青藏高原,哦 MY GOD,錯了,那就是浮點數精度損失問題。


為什麼會有損失呢?


1、如果一個浮點數的二進制表示為 1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx * 2^y ,這裡x的位數明顯超過23,這個時候,數值位就會進行截斷,只取前23位,後面的就被截斷了,當然就會損失精度了,這種問題可以用double解決,但是如果x的位數超過52,double也無能為力。


2、浮點數本身就換算不出有窮的二進制數,我們的小數部分之所以取0.375,是因為它可以用0.011表示出來,但是事實上還有一些數據是無法准確表示出來的,舉一個例子,0.2,如果大家進行乘2取整 運算,會發現 進入循環,也就無法得到准確表示,這也是造成損失的原因。


我們通過分析精度損失原因,應該可以知道,double的精度要比float的高,以及為什麼高。


好了,這篇暫時就到這裡,下一篇我們開始講數據類型了哦,很重要的哦,應該說超級重要。


本文出自 “千千阙歌” 博客,請務必保留此出處http://qianqianquege.blog.51cto.com/8004200/1304575

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved