SylixOS中時間結構體探究

1. 相關名詞解釋

1.1      什麼是timeval結構體

    timeval結構體在SylixOS系統中的定義如程序清單1.1所示:

程序清單1.1 timeval結構體定義

struct timeval {time_t         tv_sec;                /*  seconds                     */LONG           tv_usec;               /*  microseconds                */};

 

    tv_sec儲存從UTC 1970年1月1日00時00分00秒到創建結構體時的秒數,tv_usec爲微秒數。在SylixOS下,time_t的實際類型爲long long型,大小爲8個字節,長度64位。

2. 使用timeval結構體存在的問題

2.1      Linux下的timeval結構體

    Linux下的timeval結構體定義爲程序清單2.1所示:

程序清單2.1 timeval結構體定義

struct timeval {__time_t           tv_sec;            /*  seconds                     */__suseconds_t      tv_usec;           /*  microseconds                */};

    其中tv_sec和tv_usec的儲存內容與SylixOS下一致,但是在32位的Linux系統中,__time_t實際類型爲long int,大小爲4個字節,長度32位。

2.2      結構體不一致造成的問題

2.2.1   計時長度問題

    由於32位的Linux系統使用timeval結構體中的tv_sec長度爲32位,則其最大值爲2^32-1,意味着到UTC時間2038年1月19號03點14分07秒過後,32位Linux系統存儲的時間變量將會溢出,造成系統將時間混亂。這很可能會引起軟件故障,甚至是系統癱瘓。

    而使用SylixOS系統,無論是32位系統或是64位系統,tv_sec的長度均爲64位,時間最多可以使用到UTC時間292,277,026,596年12月04日15時30分08秒則基本不會遇到這類溢出問題。

 

2.2.2   參數傳入問題

    在完善glib移植的過程中,遇到這樣一個問題:依賴glib庫的lcm庫,需要將GTimeVal結構體作爲參數傳入select函數。

    其中GTimeVal結構體的定義爲程序清單2.2 所示:

程序清單2.2 GTimeVal結構體定義

typedef             long             glong;typedef  struct    _GTimeVal         GTimeVal;struct _GTimeVal

{

glong   tv_sec;

glong   tv_usec;

};

    傳入方式爲程序清單2.3 所示:

程序清單2.3 GTimeVal傳入select函數

GTimeVal selectto;status=select (recvfd + 1,&readfds,0,0, (struct timeval*) &selectto);

    由於lcm庫是基於32位Linux系統的,select函數接受的參數爲timeval結構體類型的指針。雖然對於傳入的指針做了強制類型轉換,在編譯時不會報錯,但實際運行中,SylixOS系統尋找的地址爲8字節+4字節,而實際只儲存了4字節+4字節的內容,導致tv_usec變量獲取值異常,出現不可預知的錯誤。

    所以需要手動添加timeval結構體,賦值後將timeval結構體傳入select函數,如程序清單2.4 所示:

程序清單2.4 傳參修改方法

#ifdef SYLIXOS        struct timeval selectt;

    selectt.tv_sec = selectto.tv_sec;

    selectt.tv_usec = selectto.tv_usec;

    status=select (recvfd + 1,&readfds,0,0, (struct timeval*) &selectt);#else    status=select (recvfd + 1,&readfds,0,0, (struct timeval*) &selectto);#endif

 

2.2.3   結構體大小問題

    使用sizeof運算符求SylixOS下timeval結構體的大小時,獲得的值爲12;32位Linux下獲得值爲8;在32位Windows平臺仿造SylixOS下定義timeval結構體,獲得其大小爲16。

    這涉及了結構體字節對齊的問題,在用sizeof運算符求算某結構體所佔空間時,並不是簡單地將結構體中所有元素各自佔的空間相加。從理論上講,對於任何變量的訪問都可以從任何地址開始訪問,但是事實上不是如此,實際上訪問特定類型的變量只能在特定的地址訪問,需要各個變量在空間上按一定的規則排列,而不是簡單地順序排列,這就是內存對齊。

    內存對齊的原則爲:

    1.結構體每個成員相對結構體首地址的偏移量是對齊參數的整數倍,如有需要會在成員之間填充字節。編譯器在爲結構體成員開闢空間時,首先檢查預開闢空間的地址相對於結構體首地址的偏移量是否爲對齊參數的整數倍,若是,則存放該成員;若不是,則填充若干字節,以達到整數倍的要求。

    2.結構體變量所佔空間的大小是對齊參數大小的整數倍。如有需要會在最後一個成員末尾填充若干字節使得所佔空間大小是對齊參數大小的整數倍。

    不同類型變量的長度與自身對齊參數如表2.5 所示:

表2.5 變量的長度與自身對齊參數



char

short

Int

float

double

指針

Windows(32位)

VisualStudio2010

長度

1

2

4

4

8

4

自身對齊參數

1

2

4

4

8

4


Linux(32位)

GCC

長度

1

2

4

4

8

4

自身對齊參數

1

2

4

4

4

4


SylixOS(32位)

GCC

長度

1

2

4

4

8

4

自身對齊參數

1

2

4

4

4

4


 

    從上面可以發現,在Windows(32)/ VisualStudio2010下各種類型的變量的自身對齊參數就是該類型變量所佔字節數的大小,而在Linux(32)/GCC下double類型的變量自身對齊參數是4,是因爲Linux(32)/GCC下如果該類型變量的長度沒有超過CPU的字長,則以該類型變量的長度作爲自身對齊參數,如果該類型變量的長度超過CPU字長,則自身對齊參數爲CPU字長,而32位系統其CPU字長是4,所以Linux(32)/GCC下double類型的變量自身對齊參數是4,如果是在Linux(64)下,則double類型的自身對齊參數是8。SylixOS系統也與Linux系統類似。

    所以構造相同的結構體timeval在Windows下與32位SylixOS、32位Linux在內存中所佔大小存在差異,需要在移植中注意。

3. 總結

    SylixOS與Linux、Windows存在差異,即使系統接口名稱一樣,參數類型看似一致,仍可能存在不兼容的情況。有些時候甚至編譯運行都不會出錯,但確實存在問題,移植時需要謹慎。

4. 參考資料

    《SylixOS應用程序開發手冊》

    《RealEvo-IDE使用手冊》


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章