传说中的CAFEBABE到底在哪儿?
大概在06年,我看到了一本書,叫做<<深入Java虛擬機>>。
在周志明那本神書《深入理解Java虛擬機》出來之前,這本書應(yīng)該是唯一一本講JVM的書, 對Java class文件格式,執(zhí)行引擎講得特別詳細。
我看了一遍看完了以后就“熱血沸騰”:原來Java 的class 文件格式是這樣的啊!也許我也可以寫一個JVM了!
于是我就開始琢磨, 先寫程序去解析.class文件, 然后寫一個小的執(zhí)行引擎,去執(zhí)行那些字節(jié)碼。?
作為第一步,我要寫個小程序去讀取硬盤上的.class文件,然后看看它的頭四個字節(jié)是不是著名的魔數(shù):“CAFE BABE”
第一個字節(jié)實際的輸出結(jié)果讓我大跌眼鏡:?-54 !
這是怎么回事呢?說好的CA呢?
這個問題讓我想了很久,后來終于想明白了,CA 是16進制字符,變成二進制就是 1100 1010 , Java內(nèi)部使用補碼表示數(shù)字的,把1100 1010看作二進制補碼,它對應(yīng)的十進制可不就是-54嘛!
原來都是補碼惹的禍!
那計算機為什么用補碼呢?一個重要的原因就是簡化電路的設(shè)計:把整數(shù)的加減法統(tǒng)統(tǒng)變成加法來運算。
比如一個4位的計算機,能表示的數(shù)字是 0 ~ 15?
在做加法的時候非常簡單:?
8+3(十進制) = 1000 + 0011 = 1011 = 11 (十進制)
我們可以設(shè)計一套簡單的數(shù)字電路(與門,或門等)來實現(xiàn)這個加法運算。?
但是減法怎么辦呢?難道再設(shè)計另外一套電路?這就浪費了。
于是人們就引入一個‘補數(shù)?'的概念, 例如 3的補數(shù) 是 13, 4的補數(shù)是12, ?5 的補數(shù)是11......
當你計算7減去3 的時候, 可以變成 7加上3 的補數(shù), 即 7 + 13 :?
7-3 = 0111- 0011 (二進制3) = 0111 + 1101(二進制13) = 10100 ?
10101已經(jīng)是5位了,溢出了, 去掉最高位是 0100 ,就是十進制4 了。?
那二進制的“補數(shù)”怎么得出呢?人們想出了一個異常簡單, 又特別適合計算機電路的算法,?對二進制數(shù)的所有位取反, 然后加1:
3 -> 0011 -> 1100 (取反) -> 1101 (加1)
這種方法是不是很神奇?只用一套加法電路和補碼電路就可以高效地實現(xiàn)加法和減法了。?
等等,負數(shù)怎么辦?我們手寫的時候,可以在一個數(shù)前加個負號, 就可以表示,但是對計算機來說,它必須得用某一位來表達正負,比如用這種方法:
最高位的0 表示整數(shù),1 表示負數(shù)。?
真正有效的數(shù)字只剩下3位了, 正數(shù)的范圍是從1 到7 ,負數(shù)的范圍從 -1到-7 ,不過這里出現(xiàn)了兩個零!一個正0 , 一個負0 , 這肯定不好!
改進一下,把那個負0 認為是-8吧,這樣還能多表示一個數(shù)字!
這樣,數(shù)字的范圍變成了從[-8 ,7]? 。?
推廣一下,在編程語言中,對于n位整數(shù),它的取值范圍是[-2^(n-1) ~ 2^(n-1) - 1] ?,正數(shù)要比負數(shù)少一個。?
但是之前的減法變加法的規(guī)則還能用嗎?我們試試:
7-4 ?= 7+(-4) =?0111 +1100 = 10011 -> 0011 (舍掉最高位) = 3, 正確!
4-7 = 4+(-7) = 0100 + 1001 = 1101 = -3 ?,正確!
注意,用這種辦法,連符號位都參與了運算。?
總結(jié)一下,?在計算機內(nèi)部,是使用補碼來表示二進制數(shù), 如果是一個正數(shù), 補碼就是它本身, ?如果是個負數(shù), 需要把除了符號位之外的二進制數(shù)進行取反加一的操作。?
回到我們開頭的問題, 如何正確地把第一個字節(jié)變成16進制字符串“CA”,然后展示出來呢?用這個函數(shù)就可以了:
總結(jié)
以上是生活随笔為你收集整理的传说中的CAFEBABE到底在哪儿?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干货 | 携程基于Quasar协程的NI
- 下一篇: Redis 10亿数据量只需要100MB