• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 64bit需要做的改變

    發表于:2007-07-04來源:作者:點擊數: 標簽:
    最近64bit以更低的代價開放到了廣大的用戶面前,對于需要更大的內存空間,或者更精確的浮點數計算的 開發 者來說,無疑提供了更多的方便。這篇文章的目的是要讀者了解對于32bit的源代碼向64bit轉移所要做的工作。 事實上來說,32bit的代碼可以很方便的移植到6
    最近64bit以更低的代價開放到了廣大的用戶面前,對于需要更大的內存空間,或者更精確的浮點數計算的開發者來說,無疑提供了更多的方便。這篇文章的目的是要讀者了解對于32bit的源代碼向64bit轉移所要做的工作。

    事實上來說,32bit的代碼可以很方便的移植到64位機上,因為64位提供了對32位很好的支持,只有在你有以下的需要的時候,嘗試去修改你的代碼

  • 獲得超過4GB內存的支持。
  • 獲得超過2G大小文件的支持
  • 獲得更精確的浮點數運算
  • 獲得64位機優化的數學運算庫
  • 否則,只需要重新編譯你的32位代碼,that's ok!

    1。ILP32和LP64 數據模式

    大多數unix系統的數據模式是采用LP64bit的,long和pointer是8個字節64位的,相對于32bit的4個字節。將來windows或許會采用一種數據模式LLP64,只是對于pointer采用64bit,其他的和32位一樣。這里以表格的方式顯示兩者之間的差別

    Data TypeILP32 (bits)LP64 (bits)
    char8No change
    short16No change
    int32No change
    long long64No change
    long3264
    pointer3264

    基本上移植到64bit的錯誤都是來自誤以為int long pointer都是64bit的,實際則不然。下面是一個程序演示了這個錯誤。

    1      int *myfunc(int i)
    2      {
    3               return(&i);
    4      }
    5
    6       int  main(void)
    7       {
    8               int     myint;
    9               long    mylong;
    10              int     *myptr;
    11
    12        char *name = (char * ) getlogin();
    13
    14                printf("Enter a number %s: ", name);
    15               (void) scanf("%d", &mylong);
    16                myint = mylong;
    17                myptr = myfunc(mylong);
    18                printf("mylong: %d  pointer: %x \n", mylong, myptr);
    19                myint = (int)mylong;
    20                exit(0);
    21
    22      }
    上面的代碼是錯誤的,需要進行修正。

    移植的第一項工作,是讓編譯器能檢測到64位的錯誤。這根據編譯器的不同而變化。對于IBM的XL 編譯器家族來說,有用的參數是-qwarn64 -qinfo=pro. 把你的代碼編譯成64bit需要加上-q64,對于gclearcase/" target="_blank" >cc編譯器來說則是加上-m64,下面列舉一些編譯64位一些有用的gcc參數。

    OptionDescription
    -WpaddedWarns that padding was added to the structure.
    -WformatCheck calls to printf and scanf have correct format strings.
    -Wsign-compareWarn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned.
    -Wsign-compareWarn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned.
    -WconversionWarn if a prototype causes a type conversion that is different from what would happen to the same argument in the absence of a prototype.
    -Wpointer-arithWarn about anything that depends on the function pointer or of void *.

    下面演示以下編譯上面代碼所出現的提示信息。

    %  xlc -q64  -qformat=all -qwarn64 test.c

    "test.c", line 12.30: 1506-745 (I) 64-bit portability: possible incorrect pointer through conversion of int type into pointer.
    "test.c", line 15.36: 1506-1191 (W) Invalid int format for long argument type in argument 2.
    "test.c", line 16.25: 1506-742 (I) 64-bit portability: possible loss of digits through conversion of long int type into int type.
    "test.c", line 17.32: 1506-742 (I) 64-bit portability: possible loss of digits through conversion of long int type into int type.
    "test.c", line 18.39: 1506-1191 (W) Invalid int format for long argument type in argument 2.
    "test.c", line 19.25: 1506-742 (I) 64-bit portability: possible loss of digits through conversion of long int type into int type.

    2。缺少原型的轉換方面的考慮。

    上面的代碼char *name = (char * ) getlogin();

    會出現錯誤的,32位的int要轉換成64位會出現錯誤的,要避免這種錯誤,include正確的頭文件<unistd.h>,里面有getlogin()的原型。

    3。制定數據格式的錯誤

    (void) scanf("%d", &mylong);

    要避免這個錯誤,修改成這樣(void) scanf("%ld", &mylong);

    printf("mylong: %d  pointer: %x \n", mylong, myptr);
    修改成printf("mylong: %ld  pointer: %p \n", mylong, myptr);

    4.賦值的錯誤

    myint = mylong;
    錯誤出現在64位的值賦給32位的

    5.數值參數的傳輸錯誤

    myptr = myfunc(mylong);會出現傳遞時的轉換類型錯誤

    6.類型強制轉換出現的錯誤

    myint = (int)mylong;

    int length = (int) strlen(str);
    在LP64模式中strlen返回的是unsigned long,雖然一般不會出現錯誤,但是在大于2GB的時候,盡管不大可能,但是會出現潛在的錯誤。

    7.更多的微妙的錯誤

    編譯器會發現大多數的潛在的類型轉換方面的錯誤,但是你不能僅僅依賴于編譯器。

    #define INVALID_POINTER_VALUE 0xFFFFFFFF
    在32位上上面的宏定義會被經常地用來測試-1,但是在64位機上,這個數值卻不是-1,而是4294967295。在64位機上-1是0xFFFFFFFFFFFFFFFF。要避免這個錯誤,利用const來聲明,并指定signed還是unsigned

    const signed int INVALID_POINTER_VALUE = 0xFFFFFFFF;
    上面的代碼在32位和64位機上都會工作的很好。

    還有就是32位機上的代碼如下

    int **p; p = (int**)malloc(4 * NO_ELEMENTS);
    這個代碼犯了如下的錯誤就是認為sizeof(int) ==  sizeof(int *)

    實際上在64位上是不對的。

    8.signed和unsigned的錯誤

    long k;
    int i = -2;
    unsigned int j = 1;

    k = i +  j;

    printf("Answer: %ld\n", k);
    以上的代碼在32位機上會得出-1。但是在64位機上卻不是的。結果會是4294967295。原因是i+j得到的會是unsigned的值,而這個值卻會賦給long的k,要避免這個錯誤,需要進行修改如下:

    k = i + (int)j;

    9.union的錯誤


    下面是一個很常見的結構體:

    typedef struct {
        unsigned short bom;
        unsigned short cnt;
        union {
            unsigned long bytes;
            unsigned short len[2];
        } size;
    } _ucheader_t;
    32位機上會工作的很好,但是在64位機上不然。原因是64位機上long 等于4個short.要把unsigned long 修改成 unsigned int. 才能工作好。必須要注意這個細節。

    10.big endian和little endian導致的錯誤

    在32位機上的代碼有些移植到64位機上出現錯誤與否還和機器的big endian或者little endian有關。比如下面的代碼。

    long k;
    int *ptr;

    int main(void)
    {
        k = 2 ;
        ptr = &k;
        printf("k has the value %ld, value pointed to by ptr is %ld\n",              k, *ptr);
        return 0;
    }

    這段代碼在32bit機上編譯不會出現錯誤,因為long 和pointer都是32bit,但是在64位機上不然,盡管如此,如果在little endian的64位機上編譯的話,仍然會得到正確的2,但是在big endian的情況下,則會得到0。

    如果有疑問的話,下面詳細解釋一下。

    Memory AddressLittle Endian LP64Big Endian LP64
    0x0x7fbfffdca0 ptr0x020x00
    0x0x7fbfffdca10x000x00
    0x0x7fbfffdca20x000x00
    0x0x7fbfffdca30x000x00
    0x0x7fbfffdca40x000x00
    0x0x7fbfffdca50x000x00
    0x0x7fbfffdca60x000x00
    0x0x7fbfffdca70x00

    0x02

    11.64位機上性能的降低

    這個問題是由于64位機的數據結構的膨脹,對于內存需要的增加,以及存儲空間的增加所致。要減少這方面的損失,你可以精心改變你的數據結構中變量定義的順序。比如下面的例子


    javascript:window.open(this.src);" style="CURSOR: pointer" onload="return imgzoom(this,550)">

     
    12.如何測試你的64位代碼

    定義一些宏來完成目標,下面是示例:

    #if defined (__LP64__) || defined (__64BIT__) || defined (_LP64) || (__WORDSIZE == 64)
       printf("I am LP64\n");
    #else
       printf("I am ILP32 \n");
    #endif

    13.64位文件和32位文件之間的彼此讀取問題

    #include <stdio.h>
    #include <inttypes.h>

    struct on_disk
    {
       /* ILP32|LP64 Sharing Issue: This should change to int32_t */
       long foo;
    };
    int main()
    {
        FILE *file;
        struct on_disk data;
    #ifdef WRITE
            file=fopen("test","w");
            data.foo = 65535;
            fwrite(&data, sizeof(struct on_disk), 1, file);
    #else
            file = fopen("test","r");
            fread(&data, sizeof(struct on_disk), 1, file);
            printf("data: %ld\n", data.foo);
    #endif
        fclose(file);
    }          

    代碼不能很好地在32位和64為對同一個文件的操作過程中工作。要fix這個錯誤,可以設置宏定義,以在64位機上對foo聲明為int32_t。要注意這個細節。

    14.fortran和c語言混合的問題

    下面兩個程序演示了這個錯誤

    void FOO(long *l);
    main ()
    {
       long l = 5000;
       FOO(&l);
    }

    subroutine foo( i )
    integer  i
    write(*,*) 'In Fortran'
    write(*,*) i
    return
    end subroutine foo

    要避免這個錯誤,需要在fortran語言中把i聲明為INTEGER*8,這相當于64位的long.

    最后,結論:64位機提供了對于更多的計算方面的更好的支持,盡管32位代碼一般來說可以移植的很好,但是,得注意這些細節方面的問題,這樣才能使你的代碼一直工作更順利。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>