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