第 1 頁 (共 1 頁)
Endian Trouble...
發表於 : 02/03/2005 7:58 pm
由 ulysses
最近在寫底層的通訊程式,用 ANSI C 寫,目標是 Porting 到不同平台,幾乎是立刻就碰到了 Endian 的問題。2 byte 以上的 short/int/long 型別都要轉換不說,最麻煩的就是這個狀況:
代碼: 選擇全部
unsigned char buffer[100];
void function1(...) {
unsigned short a, b;
unsigned short *ptr = &buffer[0];
...
*ptr++ = a;
*ptr++ = b;
...
}
void function2(...) {
unsigned int c;
c = *((int *)(&buffer[0]));
if(c==SOME_CONSTANT) {
function3 (c);
}
}
void function3(unsigned int c) {
unsigned short x = (unsigned short)(c & 0x0000FFFF); // 應該要等於 a 的
unsigned short y = (unsigned short)(c>>16); // 應該要等於 b 的
}
程式碼要能夠直接搬到 X86 平台上 Compile,
不希望維護兩份程式碼,所以不能用 Darwin 特有的 endian.h。
現在是用了一堆 #define 的 Macro 來解決這個問題,
有沒有比較高明一點的方法呢?
發表於 : 02/03/2005 9:08 pm
由 悲
發表於 : 02/03/2005 10:42 pm
由 digdog
#include <netinet/in.h>
unsigned short int htons(unsigned short int data)
相關的還有 htonl()、ntohs() 跟 ntohl(),反正就是在做你想要做的處理之前,讓它統統先變成 big-endian 就對了。
發表於 : 02/04/2005 8:23 am
由 ulysses
測試 Big Endian 的方式倒是不難,在 Mac 上會有定義『_BIG_ENDIAN』,用一個 #ifdef 來判斷就好。
htons 之類的函式不能呼叫(因為目標平台上沒有這個函式庫),自己用 #define 定義了 Macro。
只是每個數字都要特別處裡,實在很討厭。雖說 Endian 是依據 CPU Register 的配置來決定,只是想看看有沒有任何方法讓 GCC 自動處理掉這個問題...
好像想得太美了。OTZ
發表於 : 02/04/2005 9:52 am
由 digdog
ulysses 寫:
htons 之類的函式不能呼叫(因為目標平台上沒有這個函式庫),自己用 #define 定義了 Macro。
好可憐喔.... 那自己寫一個如何?
代碼: 選擇全部
uint16_t htons(uint16_t host_int) {
uint16_t big_endian_int;
uint8_t *p = (uint8_t *)&big_endian_int;
p[0] = (host_int & 0xff00) >> 8;
p[1] = host_int & 0xff;
return big_endian_int;
}
uint16_t ntohs(uint16_t big_endian_int) {
uint8_t *p = (uint8_t *)&big_endian_int;
return (p[0] << 8) + p[1];
}
ulysses 寫:
只是每個數字都要特別處裡,實在很討厭。雖說 Endian 是依據 CPU Register 的配置來決定,只是想看看有沒有任何方法讓 GCC 自動處理掉這個問題...
好像想得太美了。OTZ
你的 tool chain 是給那個平台用的?gcc 裡面有 -mwords-little-endian 這類的選項嗎?
發表於 : 02/04/2005 1:20 pm
由 ulysses
digdog 寫:ulysses 寫:
htons 之類的函式不能呼叫(因為目標平台上沒有這個函式庫),自己用 #define 定義了 Macro。
好可憐喔.... 那自己寫一個如何?
有啊,就這樣:
代碼: 選擇全部
typedef unsigned char byte_t;
typedef unsigned short word_t;
typedef unsigned long dword_t;
typedef unsigned long long qword_t;
#ifdef _BIG_ENDIAN
#define swapword(a) ((word_t)(a)>>8)|((word_t)(a)<<8)
#define swapdword(a) ((((dword_t)(a)&0xFF000000)>>24)|\
(((dword_t)(a)&0x00FF0000)>>8)|\
(((dword_t)(a)&0x0000FF00)<<8)|\
(((dword_t)(a)&0x000000FF)<<24))
#define swapqword(a) ((((qword_t)(a)&0xFF00000000000000ll)>>56)|\
(((qword_t)(a)&0x00FF000000000000ll)>>40)|\
(((qword_t)(a)&0x0000FF0000000000ll)>>24)|\
(((qword_t)(a)&0x000000FF00000000ll)>>8)|\
(((qword_t)(a)&0x00000000FF000000ll)<<8)|\
(((qword_t)(a)&0x0000000000FF0000ll)<<24)|\
(((qword_t)(a)&0x000000000000FF00ll)<<40)|\
(((qword_t)(a)&0x00000000000000FFll)<<56))
#else
#define swapword(a) ((word_t)(a))
#define swapdword(a) ((dword_t)(a))
#define swapqword(a) ((qword_t)(a))
#endif
不用說也知道,這個方式很蠢。
digdog 寫:你的 tool chain 是給那個平台用的?gcc 裡面有 -mwords-little-endian 這類的選項嗎?
有三個平台,X86、AVR mega128 和 TI 460。都是 PDA 類型的裝置。Cross Compiler 用 GCC 就可以,但是 endian 的控制就不曉得應該在 GCC 下參數,還是用 binutil 來處理。
發表於 : 02/04/2005 4:48 pm
由 digdog
ulysses 寫:
有三個平台,X86、AVR mega128 和 TI 460。都是 PDA 類型的裝置。Cross Compiler 用 GCC 就可以,但是 endian 的控制就不曉得應該在 GCC 下參數,還是用 binutil 來處理。
gcc 的部分就加參數(像是 -mb / -mbig-endian / -mwords-big-endian )
如果有用到 library 那 ld script 要改,但是爛狗看不懂,所以也沒辦法告訴你要怎麼改