記憶體表示,位運算及位元組序

2021-04-13 01:21:47 字數 2788 閱讀 6062

這篇文章始於對這麼個程式的思考:

intmain

(int

argc

, char

* argv

)

用二進位制編輯器(如ultraedit)開啟程式輸出結果檔案「test.txt」檢視,結果是:「87 d6 12 00」。如果將87d61200直接輸入計算器,轉變成十進位制數,那就是2278953472,並非我們所期待的1234567,但如果把這幾個十六進製制數倒過來,輸入0012d687到計算器,轉成十進位制數,就出現了我們想要的結果,1234567。這是乙個位元組序的問題,但在討論這個之前,我想先來討論下記憶體的表示。

粗一想,這根本不是問題,把記憶體位址和資料以表的形式列出來不就行了麼?但仔細一想,確實還有些要斟酌之處。因為:我們對記憶體「寫生」到紙上就有上下左右方位之分,而真實的記憶體,並沒有上下左右這些方位的概念,只有「高位」和「低位」的概念,記憶體電子元器件所表示的那些「0」和「1」是連續的。那究竟把高位畫在上還是畫在下?或者左?或者右?下面我來說說我的理解,按照我們常規思維,「高」通常就代表「上」,「低」就代表「下」,不僅我們中國人如此,發明電腦的老美也如此,dos的記憶體管理中有個「上位記憶體」的概念,上位記憶體英文就是「upper memory block」,居高位,在常規記憶體之上的意思,看來上高下低是沒什麼問題了吧。

那如果我們有張紙條,必須要左右繪表來描述記憶體,那究竟左高還是右高?其實這也是比較明顯的,像1234567這個整數,1明顯居高位,它是最有效力的數字,它在最左邊,所以應該用左邊來表示高位,這樣和我們的思維習慣比較相符,如果這個理由還不夠充分,那我這裡就插入「位運算」來講一下。

intmain

(int

argc

, char

* argv

)

「>>」是右位移運算子(bitwise right shift operator),「<

但!你發現沒有,這種表示規則和我們的閱讀習慣,書寫習慣完全相反。我們人類寫字都是從左到右,從上到下,(btw:ok,我承認日本人有從右到左的習慣,但這裡就別鑽牛角尖了,嘿嘿)如何見得這個衝突?看下面的**:

char

szarray[10

] =;

我們給szarray這個陣列賦初值,這麼一來,你認為szarray[0],szarray[1]分別是哪個字元?那還用想麼?當然分別是「a」和「b」,那麼szarray[0]居低位,還是szarray[1]居低位?那也根本不用想,當然是szarray[0]居低位,但回頭看看我們的賦值語句,「a」是寫在「b」的左邊的,但它卻居低位而非高位。所以我認為人的習慣還是從上往下,從左往右,把低的東西寫到高,把小的東西寫到大。至於為什麼會這樣,我也無法回答,可能要去請教下生物學家。看下面這個截圖,正好說明了這點,這是vc++中的記憶體表示法,明顯和我前面推薦的表示法相反,低位居上居左,高位居下居右。

那說了半天究竟要用哪種表示法?怎樣?知道這個是個問題了吧。我這裡也沒有標準答案,事實上兩種表示法都會出現在實際應用中,所以都需要適應。但有一點必須強調,要不就上左高位,要不就上左低位,不存在上高左低或上低左高。

好了,回到文章開始的那個位元組序的問題,我曾經被這個位元組序的問題弄得糊里糊塗,現在終於想明白,其實我當時之所以這麼難明白,主要就是位元組序這個英文單詞(endian)太能誤導人。endian這個單詞在傳統詞典裡是查不到的,但看到前邊的「end」就容易讓人想起「結束」,這真是個大錯誤,其實它和結束沒有任何關係,看它的英文解釋:the ordering of bytes in a multi-byte number,翻譯為「位元組序」就合適了。

目前有兩種常見的位元組序,即「big-endian」和「little-endian」,如果你認為「endian」含有「結束」的意思的話這裡就出差錯了,因為如果記憶體用「開始」和「結束」來描述本來就是很不清晰的,只能用「高位」和「低位」來描述,「big-endian」是把最有效力的數放在低位(這裡姑且把「低位」算「開始」吧),而「little-endian」正好相反,把最沒效力的數放在低位。

位元組序的採用和系統有關係,目前pc機上的系統都是「little-endian」,很明顯,我除錯開篇程式的這個系統使用的也是「little-endian」,據稱mac機則使用「big-endian」,可惜我只用過pc機,所以沒法在此證實了。

由於各種系統使用的位元組序可能不同,系統對數字的理解就有可能不同,那如果系統之間傳輸數字資訊的時候就可能出亂子,比如我用pc機把整型數「1234567」傳輸到一台mac機去,mac機就會把這個數字理解成「2278953472」,相差不是一點點。所以這裡就涉及到位元組序轉換的問題。也就是那幾個常用的函式:htons,htonl,ntohs,ntohl。這裡就不展開說了。

最後還有個問題,假如兩個系統用的都是同一種位元組序,那在它們之間傳輸資料是否還需要用這幾個函式轉換位元組序?答案是最好用,因為網路也有它自己的位元組序(big-endian),一些包在網上傳輸的時候可能要設定一些要讓網路理解的引數,這種轉換還是必須的,儘管有時候看起來不轉換也沒問題,但大家都依循這個規則不是更好麼?

記憶體表示位運算及位元組序

原文 intmain int argc char argv 用二進位制編輯器 如ultraedit 開啟程式輸出結果檔案 test.txt 檢視,結果是 87 d6 12 00 如果將87d61200直接輸入計算器,轉變成十進位制數,那就是2278953472,並非我們所期待的1234567,但如果...

記憶體位元組序

記憶體位元組序 一 位元組順序 資料在記憶體中的存放順序。分為小端 little endian 和大端位元組順序 big endian 資料在記憶體中是乙個位元組乙個位元組來儲存的,因為乙個記憶體單元的大小就為乙個位元組。1.小端順序 低位元組資料存放在記憶體低位址處,高位元組資料存放在記憶體高位址...

位元組對齊 位域 位元組序

測試環境 win 7 64bits,vmware workstation 12 pro,ubuntu 15.10 64bits,使用gcc version 5.2.1 20151010 include pragma pack 1 14,11,11 pragma pack 2 16,12,12 pra...