32位程序和64位程序这些区别你知道吗?
我們在編寫C/C++程序時,32位程序和64位程序的代碼有何區別?如何編寫既可以編譯成32位程序又可以編譯成64位程序的代碼?
代碼上的區別
實際上,對于32位程序和64位程序來說,代碼上的區別不大,嚴格來說,甚至是一樣的,它的主要區別在于一些基本數據類型占用的字節長度不一樣(注:這里僅針對類Unix平臺)
| long | 4 | 8 |
| unsigned long | 4 | 8 |
| 指針 | 4 | 8 |
當然這里的long包括一些用它定義的類型,如time_t,它的長度也是有區別的,關于time_t,還有一個有意思的問題《什么是2038問題》。
除此之外,其默認對齊字節數,也不一樣,32位程序為4字節,64位程序默認為8字節。關于字節對齊,可參考《理一理字節對齊的那些事》。
可執行文件上的區別
來看個小例子吧,看看他們有何區別。
//來源:公眾號編程珠璣 //作者:守望先生 test.c #include<stdio.h> struct?Test {int?a;long?b; }; int?main(void) {printf("sizeof(long)?=?%zu\n",sizeof(long));?//long類型占用字節數printf("sizeof(unsigned?long)?=?%zu\n",sizeof(unsigned?long));//unsigned?long類型占用字節數struct?Test?test?=?{1,2};printf("sizeof(struct?Test)?=?%zu\n",sizeof(test));//用于測試對齊字節數printf("sizeof(pointer)?=?%zu\n",sizeof(&test));?//指針占用字節數return?0; }如果你的系統是64位,默認編譯為64位程序,而如果需要編譯為32位程序,則需要帶上-m32參數,如果你的系統是32位的,那么是不能直接運行64位程序的,但是如果是64位的,是可以運行32位程序的。(實際上你在下載軟件的時候需要選擇位數的時候,就需要注意了,如果你的系統32位的, 但是你下載了一個64位的程序包,自然是不可用的,但是反過來卻可以。)
編譯為32位程序運行:
$?gcc?-o??test32?test.c?-m32 $?./test32 sizeof(long)?=?4 sizeof(unsigned?long)?=?4 sizeof(struct?Test)?=?8 sizeof(pointer)?=?4編譯位64位程序運行:
$?gcc?-o?test64?test.c? $?./test64? sizeof(long)?=?8 sizeof(unsigned?long)?=?8 sizeof(struct?Test)?=?16 sizeof(pointer)?=?8通過運行結果,我們也可以看出前面提到的差別。
那么可執行文件本身有什么差別呢?
$?readelf?-h?test32 ELF?Header:Magic:???7f?45?4c?46?01?01?01?00?00?00?00?00?00?00?00?00?Class:?????????????????????????????ELF32Data:??????????????????????????????2's?complement,?little?endianVersion:???????????????????????????1?(current)OS/ABI:????????????????????????????UNIX?-?System?VABI?Version:???????????????????????0Type:??????????????????????????????EXEC?(Executable?file)Machine:???????????????????????????Intel?80386(...)可以看到Class屬性標識為ELF32。
而對于64位:
readelf?-h?test64 ELF?Header:Magic:???7f?45?4c?46?02?01?01?00?00?00?00?00?00?00?00?00?Class:?????????????????????????????ELF64Data:??????????????????????????????2's?complement,?little?endianVersion:???????????????????????????1?(current)OS/ABI:????????????????????????????UNIX?-?System?VABI?Version:???????????????????????0Type:??????????????????????????????EXEC?(Executable?file)Machine:???????????????????????????Advanced?Micro?Devices?X86-64它的屬性為ELF64。實際上我們可以通過readelf發現很多信息。
例如你在進行交叉編譯后出現鏈接錯誤或者最后的執行程序在目標機器無法運行,則可以查看Machine部分,看看程序是否能在你想要的平臺運行。
例如64位程序中的Machine中顯示的是Advanced Micro Devices X86-64,至少說明它在arm平臺是沒法正常運行的。
elf文件中的一些相關信息已經在《一個elf文件包含了多少信息?》中介紹了,有興趣的可以移步前往閱讀。
一個程序最大能申請多少內存空間?
還記得這道面試題嗎?如果你只是回答Linux理論最大不超過3G,windows不超過G,那肯定是不完整的,這里必須要區分32位程序和64位程序。
這一點在《解引用NULL為什么會掛死?》中已經有所提及。32位決定了其虛擬地址空間的最大值為2^32,即4G,除去操作系統占用的1G左右,剩下3G左右,當然了這里面3G包含了所有代碼,數據等,總結就是,最終能使用的不超過3G。不到3G的地址空間。(注這里并不表示它只能訪問計算機4G的內存,而是表示最大尋址范圍為4G)。那么64位的虛擬地址空間擴展到了17179869184G,所以,看出差別了嗎?
通過上面簡單的分析可以發現,64位程序理論能使用的內存是驚人的,而32位程序卻非常有限,除此之外,還有一個在《什么是2038問題》》中提到的問題,就是2038年后,32位程序將很難正常使用時間相關的處理。
當然了,64位系統通常能夠支持更高精度的浮點運算。
同時支持32位和64位代碼編寫原則
基于前面提到的原因,很多傳統系統都開始著手移植到64位系統上,而如果原先代碼就非常規范的話,移植工作還算比較輕松,鏈接64位庫,編譯成64位程序即可,但是如果沒有遵循以下原則,那么工作量就比較大了:
-
依賴long類型和指針類型占用空間大小以及其表示范圍
當然,對于這個原則,其表現可能非常多。
long和int混用
例如:
void?test(long?len) {int?localLen?=?len;xxxx; }這里很明顯可能會發現截斷。最常見的就是:
int?len?=?sizeof(xxx);當然,這里大多數情況下也不會有太大問題,直到其長度大于int表示范圍。
慎用掩碼定義
我們可能經常需要定義一些掩碼:
long?mask?=?OxFFFFFFFFL;在 32 位系統上,這會將所有位都置位(每位全為 1),但是在 64 位系統上,只有低 32 位被置位了。結果是這個值是 0x00000000FFFFFFFF。
如果希望所有位置1,那么可以:
打印指針
32下,這樣的沒問題的:
int?a?=?10; int?*p?=?&a; printf("%x",p);但是64位下,打印不完全。自然要使用:
printf("%p",p);傳送結構體數據
在32位和64位系統中,其默認對齊字節數是不一樣的。
strcut?test {int?a;long?b; }如果對方是64位,發送過來上述結構體數據,而你的是32位程序,可想而知,結果并不會如你所愿。前面占用空間16字節,而后者占用空間8字節。
顯示定義long
如果你的數據類型是long,那么可以使用L顯示說明:
long?i?=?1?<<?a;上面的寫法建議換成:
long?i??=?1L?<<?a;避免數據被截斷。
總結
關于這樣的點還有很多,這里不一一介紹。本文簡單介紹了32位程序和64位程序的區別,以及移植過程中需要注意的原則。實際上編寫同時能夠運行在32位和64位系統上的整體原則基本如下:
-
不要試圖假定數據類型的占用空間
-
顯示區別使用int和long
而前面提到的一些問題,其實通過一些代碼檢查工具就很容易發現了,不放過小的警告,基本能解決大部分問題。
關注公眾號【編程珠璣】,獲取更多Linux/C/C++/數據結構與算法/計算機基礎/工具等原創技術文章。后臺免費獲取經典電子書和視頻資源
總結
以上是生活随笔為你收集整理的32位程序和64位程序这些区别你知道吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: recycleView的页面跳转设计
- 下一篇: 二、网络编程