日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
講解一下Linux64位程序移植

1 概述

Linux下的程序大多充當(dāng)服務(wù)器的角色,在這種情況下,隨著負(fù)載量和功能的增加,服務(wù)器所使用內(nèi)存必然也隨之增加,然而32位系統(tǒng)固有的4GB虛擬地址空間限制,在如今已是非常突出的問(wèn)題了;另一個(gè)需要改進(jìn)的地方是日期,在Linux中,日期是使用32位整數(shù)來(lái)表示的,該值所表示的是從1970年1月1日至今所經(jīng)過(guò)的秒數(shù),這在2038年就會(huì)失效,但是在64位系統(tǒng)中,日期是使用64位整數(shù)表示的,基本上不用擔(dān)心其會(huì)失效。在這種情況下,將服務(wù)器移植到64位系統(tǒng)下,幾乎成了必然的選擇。要獲得能在64位系統(tǒng)下運(yùn)行的程序,特別是達(dá)到只維護(hù)同一套代碼就能獲得在32位及64位系統(tǒng)下都能運(yùn)行的程序,編碼時(shí)需遵循一定的原則,是一個(gè)較為繁瑣的過(guò)程。雖然有一些高級(jí)語(yǔ)言不會(huì)受這些數(shù)據(jù)類別變化的影響,但是C/C++的確會(huì)受到影響。下面,我們先來(lái)了解一下64位數(shù)據(jù)模型,為后面的介紹打下鋪墊。

創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計(jì)制作、網(wǎng)站設(shè)計(jì)、十堰鄖陽(yáng)網(wǎng)絡(luò)推廣、成都微信小程序、十堰鄖陽(yáng)網(wǎng)絡(luò)營(yíng)銷、十堰鄖陽(yáng)企業(yè)策劃、十堰鄖陽(yáng)品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供十堰鄖陽(yáng)建站搭建服務(wù),24小時(shí)服務(wù)熱線:18982081108,官方網(wǎng)址:www.cdcxhl.com

2 64位系統(tǒng)數(shù)據(jù)模型

2.1 LP64/ILP64/LLP64

下面的表格說(shuō)明了32位和64位數(shù)據(jù)模型在各個(gè)數(shù)據(jù)類別上的區(qū)別,這里的I是指int,L是指long,P是指pointer:

Datatype LP64 ILP64 LLP64 ILP32 LP32
char 8 8 8 8 8
short 16 16 16 16 16
int 32 64 32 32 16
long 64 64 32 32 32
long long 64 64 64 64 64
pointer 64 64 64 32 32

顯示詳細(xì)信息

表2.1

這3個(gè)64位模型(LP64、LLP64和ILP64)之間的區(qū)別在于非浮點(diǎn)數(shù)據(jù)類型。當(dāng)一個(gè)或多個(gè)C數(shù)據(jù)類型的寬度從一種模型變換成另外一種模型時(shí),應(yīng)用程序可能會(huì)受到很多方面的影響。這些影響主要可以分為兩類:

  • 數(shù)據(jù)對(duì)象的大小。編譯器按照自然邊界對(duì)數(shù)據(jù)類型進(jìn)行對(duì)齊;換而言之,32位的數(shù)據(jù)類型在64位系統(tǒng)上要按照32位邊界進(jìn)行對(duì)齊,而64位的數(shù)據(jù)類型在64位系統(tǒng)上則要按照64位邊界進(jìn)行對(duì)齊。這意味著諸如結(jié)構(gòu)或聯(lián)合之類的數(shù)據(jù)對(duì)象的大小在32位和64位系統(tǒng)上是不同的。
  • 基本數(shù)據(jù)類型的大小。通常關(guān)于基本數(shù)據(jù)類型之間關(guān)系的假設(shè)在64位數(shù)據(jù)模型上都已經(jīng)無(wú)效了。依賴于這些關(guān)系的應(yīng)用程序在64位平臺(tái)上編譯也會(huì)失敗。例如,sizeof (int) = sizeof (long) = sizeof (pointer) 的假設(shè)對(duì)于ILP32數(shù)據(jù)模型有效,但是對(duì)于其他數(shù)據(jù)模型就無(wú)效了。

總之,編譯器要按照自然邊界對(duì)數(shù)據(jù)類型進(jìn)行對(duì)齊,這意味著編譯器會(huì)進(jìn)行“填充”,從而強(qiáng)制進(jìn)行這種方式的對(duì)齊,就像是在C結(jié)構(gòu)和聯(lián)合中所做的一樣。結(jié)構(gòu)或聯(lián)合的成員是根據(jù)最寬的成員進(jìn)行對(duì)齊的。Windows 64位系統(tǒng)采用LLP64的數(shù)據(jù)模型,從Win32到Win64就只有指針長(zhǎng)度不同,因此移植較為簡(jiǎn)單。而Linux 64位系統(tǒng)采用LP64數(shù)據(jù)模型,因此在long和pointer上,都有著和32位系統(tǒng)不同的長(zhǎng)度。

2.2 數(shù)據(jù)對(duì)齊

默認(rèn)情況下,編譯器按照自然邊界對(duì)數(shù)據(jù)類型進(jìn)行對(duì)齊;換而言之,32位的數(shù)據(jù)類型在64位系統(tǒng)上要按照32位邊界進(jìn)行對(duì)齊,而64位的數(shù)據(jù)類型在64位系統(tǒng)上則要按照64位邊界進(jìn)行對(duì)齊。

2.2.1 #pragma pack

上面談到,默認(rèn)情況下,編譯器按照自然邊界對(duì)數(shù)據(jù)類型進(jìn)行對(duì)齊,但使用編譯器指令#pragma pack可以修改對(duì)齊方式。

2.2.2 結(jié)構(gòu)體對(duì)齊舉例

struct test

{

int i1;

double d;

int i2;

long l;

}

結(jié)構(gòu)成員 在 32 位系統(tǒng)上的大小 在 64 位系統(tǒng)上的大小
struct test {
int i1; 32位 32位
32位填充
double d; 64位 64位
int i2; 32位 32位
32位填充
long l; 32位 64位
}; 結(jié)構(gòu)大小為20字節(jié) 結(jié)構(gòu)大小為32字節(jié)

顯示詳細(xì)信息

表2.2

注意,在我自己所測(cè)試的32位系統(tǒng)上,編譯器并沒有對(duì)double型數(shù)據(jù)進(jìn)行對(duì)齊,盡管它是一個(gè)64位的對(duì)象,這是因?yàn)橛布?huì)將其當(dāng)成兩個(gè)32位的對(duì)象進(jìn)行處理。

3 從32位系統(tǒng)移植到64位系統(tǒng)

3.1 基本原則

3.1.1 類型定義

不要使用C/C++中那些在64位系統(tǒng)上會(huì)改變大小的數(shù)據(jù)類型來(lái)編寫應(yīng)用程序,而是使用一些類型定義或宏來(lái)顯式地說(shuō)明變量中所包含的數(shù)據(jù)的大小和類型。有些定義可以使代碼的可移植性更好。

l ptrdiff_t:

這個(gè)值在32位系統(tǒng)下是int,在64位系統(tǒng)下是long,表示兩個(gè)指針相減后的結(jié)果。

l size_t:

這個(gè)值在32位系統(tǒng)下是unsigned int,在64位系統(tǒng)下是unsigned long,用來(lái)表示非負(fù)的大小,一般用來(lái)表示sizeof的結(jié)果或表示數(shù)組的大小。

  • int32_t、uint32_t 等:

定義具有預(yù)定義寬度的整型。

  • intptr_t 和 uintptr_t:

這2個(gè)值在32位系統(tǒng)下是int和unsigned int,在64位系統(tǒng)下是long和unsigned long,任何有效指針都可以轉(zhuǎn)換成這個(gè)類型。

3.1.2 表達(dá)式

在C/C++中,表達(dá)式是基于結(jié)合律、操作符的優(yōu)先級(jí)和一組數(shù)學(xué)計(jì)算規(guī)則的。要想讓表達(dá)式在32位和64位系統(tǒng)上都可以正確工作,請(qǐng)注意以下規(guī)則:

  • 兩個(gè)有符號(hào)整數(shù)相加的結(jié)果是一個(gè)有符號(hào)整數(shù)。
  • int和long類型的兩個(gè)數(shù)相加,結(jié)果是一個(gè)long類型的數(shù)。
  • 如果一個(gè)操作數(shù)是無(wú)符號(hào)整數(shù),另外一個(gè)操作數(shù)是有符號(hào)整數(shù),那么表達(dá)式的結(jié)果就是無(wú)符號(hào)整數(shù)。
  • int和double類型的兩個(gè)數(shù)相加,結(jié)果是一個(gè)double類型的數(shù)。此處int類型的數(shù)在執(zhí)行加法運(yùn)算之前轉(zhuǎn)換成double類型。
3.1.3 賦值
  • sizeof和數(shù)組大?。?br />

vector intArray;

……

int arraysz = (int)intArray.size();

不要int類型來(lái)接收STL數(shù)據(jù)類型的大小,而應(yīng)該使用size_t:

size_t arraysz = intArray.size();

上面這種是比較明顯的錯(cuò)誤,不明顯的錯(cuò)誤有:

for (int i = 0; i

{

……

}

這樣有可能導(dǎo)致數(shù)據(jù)截?cái)唷?/p>

  • time_t:

不要使用int類型參與時(shí)間的運(yùn)算,因?yàn)閠ime_t是long類型,在64位機(jī)器上會(huì)導(dǎo)致數(shù)據(jù)截?cái)?,原則是與時(shí)間相關(guān)的運(yùn)算都采用time_t類型。

例如在32位程序中可能有如下代碼:

long m_lastHeartBeatTime; //最后心跳時(shí)間

int GetLastHeartBeatTime()

{

return m_lastHeartBeatTime;

}

time_t currtime = GetCurrentTime();

if(currtime >= GetLastHeartBeatTime())

{

SetLastHeartBeatTime(currtime);

}

這些代碼在32位系統(tǒng)下沒有問(wèn)題,但在64位系統(tǒng)下可能會(huì)導(dǎo)致嚴(yán)重的問(wèn)題。

  • 格式化打印

vector intArray;

……

size_t arraysz = intArray.size();

32位系統(tǒng)下代碼應(yīng)為:

printf(“array size = %u”, arraysz);

64位系統(tǒng)下代碼應(yīng)為:

printf(“array size = %lu”, arraysz);

3.2 移植經(jīng)驗(yàn)

3.2.1 如何判斷一個(gè)可執(zhí)行文件是32位編譯的版本還是64位編譯的版本
  • 使用file可執(zhí)行文件名

顯示ELF 64-bit LSB executable 則是64位可執(zhí)行文件版本

顯示ELF 32-bit LSB 則是32位可執(zhí)行文件版本

  • 使用readelf -h可執(zhí)行文件名,看其中的Class

顯示ELF64是64位可執(zhí)行文件

顯示ELF32是32位可執(zhí)行文件

3.2.2 如何判斷環(huán)境是32位還是64位

代碼中:

#if __WORDSIZE == 64

#endif

腳本中:

if [ getconf LONG_BIT -eq 64 ];then

64位處理邏輯

else

32位處理邏輯

fi

3.2.3 數(shù)據(jù)定義

修改所有l(wèi)ong定義的變量為int類型,由于long類型在32位和64位下的長(zhǎng)度是不一樣的,為了避免兼容性問(wèn)題,盡量檢查和修改掉類型定義為非固定長(zhǎng)度的整數(shù)類型。

指針類型的,如果做加減等運(yùn)算處理,不能轉(zhuǎn)換為int類型,而統(tǒng)一改為intptr_t類型,比如:

intptr_toffset = (intptr_t)pCurr – (intptr_t)pBase;

3.2.4 格式化字符串的時(shí)候

#if __WORDSIZE == 64

#define FMT_SIZET “%u”

#define FMT_UINT64 “%llu”

#define FMT_INT64 “%lld”

#else

#define FMT_SIZET “%lu”

#define FMT_UINT64 “%lu”

#define FMT_INT64 “%lld”

#endif

例如:

sprintf(errorDesc,”Insufficient memory buffer size,”FMT_SIZET” needed,but only “FMT_SIZET” bytes”,unit_size,m_capacity);

當(dāng)然也可以使用系統(tǒng)定義的宏P(guān)RIu64和PRId64等來(lái)作一些文章。

3.2.5 基本數(shù)據(jù)定義

long, time_t, size_t 類型在32位和64位下的長(zhǎng)度是不一樣的,要檢查代碼中是否有time_t *,size_t 類型的指針參數(shù),由于調(diào)用傳入的變量大部分是int類型,所以將這些函數(shù)定義統(tǒng)一修改為int,同時(shí)仔細(xì)檢查所有調(diào)用的地方,傳入的指針變量長(zhǎng)度是否匹配。

比如下面的范例:

int Func1(size_t *pSize1,size_t size2); 需要修改為

int Func1(int *pSize1,size_t size2); 其中size2是非指針類型,可以不需要修改。

然后檢查調(diào)用的地方,如果傳入?yún)?shù)是非int類型,則需要修改為int類型變量傳入,比如

short shParam = 0;

Func1(&shParam,100);

要修改為

int iParam = 0;

Func1(&iParam,100);

如果是一些已經(jīng)定義好的結(jié)構(gòu)體成員,則可通過(guò)臨時(shí)變量來(lái)修改

Func(&stPlayer.shParam,100)

修改為

int iTmpParam = stPlayer.shParam;

Func(&iTmpParam,100);

stPlayer.shParam = iTmpParam;

3.2.6 time_t的加減要注意

比如下面這段代碼,在32位系統(tǒng)上運(yùn)行沒有問(wèn)題,但64位下運(yùn)行異常:

if((leftTime + xxz::framework::GetCurrentTimeVal(NULL)) > 0 && (leftTime >= 0))

{

n->expireTime = leftTime + xxz::framework::GetCurrentTimeVal(NULL);

}

else

{

n->expireTime = 0x7FFFFFFF;

}

這里在64位下,如果lefttime等于0x7FFFFFFF,則lefttime + xxz::framework::GetCurrentTimeVal(NULL)的結(jié)果為long(因?yàn)閤xz::framework::GetCurrentTimeVal(NULL)返回time_t,為long類型),因此不會(huì)溢出,這時(shí)相加的結(jié)果賦給一個(gè)整形(n->expireTime),則這個(gè)整形溢出,稱為負(fù)值,從而發(fā)生錯(cuò)誤。

改為:

if ((int64)leftTime + (int64)xxz::framework::GetCurrentTimeVal(NULL) >= (int64)0x7FFFFFFF)

{

dstTime = 0x7FFFFFFF;

}

else

{

dstTime = leftTime + xxz::framework::GetCurrentTimeVal(NULL);

}

3.3 移植步驟

1 修改代碼,主要注意以下事項(xiàng)

去除所有的long,替換為固定大小的類型,如int32_t, int64_t等。

時(shí)間相關(guān)類型的全部用使用time_t來(lái)進(jìn)行處理。

pointer之間的加減法使用intptr_t來(lái)存儲(chǔ)結(jié)果,不要在pointer和int之間相互轉(zhuǎn)換。

如果必須用size_t,比如STL,則傳值賦值都用size_t,不要在int和size_t之間相互轉(zhuǎn)換,以免結(jié)果被截?cái)唷?/p>

格式化字符串使用如下的兼容性定義來(lái)處理,避免告警:

#if __WORDSIZE == 64

#define FMT_SIZET “%u”

#else

#define FMT_SIZET “%lu”

2 替換外部庫(kù)

這一步比較難,因?yàn)橛行┩獠繋?kù)沒有64位版本,這就有可能需要推動(dòng)外部庫(kù)的64位化工作,或者將這部分功能挪到其它進(jìn)程。

3 運(yùn)營(yíng)環(huán)境

修改腳本支持64位環(huán)境

一些數(shù)據(jù)需要用64位程序重新生成,供程序使用

4 總結(jié)

主流的硬件供應(yīng)商最近都在擴(kuò)充自己的64位產(chǎn)品,這是因?yàn)?4位平臺(tái)可以提供更好的性能和可伸縮性。32位系統(tǒng)的限制,特別是4GB的虛擬內(nèi)存上限,已經(jīng)極大地刺激很多公司開始考慮遷移到64位平臺(tái)上。了解如何將應(yīng)用程序移植到64位體系結(jié)構(gòu)上可以幫助我們編寫可移植性更好且效率更高的代碼。


當(dāng)前標(biāo)題:講解一下Linux64位程序移植
本文網(wǎng)址:http://www.dlmjj.cn/article/cdgdcpe.html