2012-05-17 34 views
1

首先,我還是個學生。所以我不是很有經驗。C中的字節如何存儲?

我正在使用一塊藍牙硬件,並使用其協議發送命令。協議要求數據包首先以每個數據包字段的LSB發送。

我收到錯誤信息包給我,說明我的CRC值錯了,所以我做了一些調查。我發現了這個問題,但我在這個過程中感到困惑。

以下是一些GDB輸出和其他信息,闡明瞭我的困惑。

我送一包看起來應該像這樣的:

|Start Flag| Packet Num | Command | Payload | CRC | End Flag| 
    0xfc  0x1  0x0 0x8 0x0 0x5 0x59 0x42 0xfd 

下面是一些GDB輸出:

print /x reqId_ep 
$1 = {start_flag = 0xfc, data = {packet_num = 0x1, command = {0x0, 0x8}, payload = { 
    0x0, 0x5}}, crc = 0x5942, end_flag = 0xfd} 

reqId_ep是我送包的變量名。它看起來一切都很好,但是我收到來自它的CRC錯誤代碼,所以一定是錯誤的。

在這裏,我檢查十六進制9個字節,從我的包的地址開始發送:

x/9bx 0x7fffffffdee0 
0xfc 0x01 0x00 0x08 0x00 0x05 0x42 0x59 0xfd 

而且這裏的問題變得很明顯。 CRC不是LSB第一。 (0x42 0x59)

要解決我的問題,我刪除了htons(),我設置了我的CRC值等於。

這裏是上面相同的輸出,而不htons():

p/x reqId_ep 

$1 = {start_flag = 0xfc, data = {packet_num = 0x1, command = {0x0, 0x8}, payload = { 
    0x0, 0x5}}, crc = 0x4259, end_flag = 0xfd} 

這裏的CRC值不LSB。

但後來:

x/9bx 0x7fffffffdee0 
0xfc 0x01 0x00 0x08 0x00 0x05 0x59 0x42 0xfd 

這裏的CRC值LSB第一。

所以顯然C的存儲是LSB第一?有人能爲這種情況投下一些知識嗎?非常感謝你。

+1

這取決於您正在運行的處理器。大於一個字節的數字值可以存儲爲「big-endian」或「little-endian」。 (谷歌的條款和研究。) –

回答

4

這在計算與字節序做: http://en.wikipedia.org/wiki/Endianness#Endianness_and_operating_systems_on_architectures

例如,值4660(基10)是十六進制爲0x1234。在Big Endian的系統,它會被存儲在內存中1234而小端系統,它會被存儲爲3412

。如果你想避免這種問題,在未來,它可能只是最簡單的創建一個大數組或無符號字符的結構體,並在其中存儲各個值。

如:

|Start Flag| Packet Num | Command | Payload | CRC | End Flag| 
    0xfc  0x1  0x0 0x8 0x0 0x5 0x59 0x42 0xfd 

typedef struct packet { 
    unsigned char startFlag; 
    unsigned char packetNum; 
    unsigned char commandMSB; 
    unsigned char commandLSB; 
    unsigned char payloadMSB; 
    unsigned char payloadLSB; 
    unsigned char crcMSB; 
    unsigned char crcLSB; 
    unsigned char endFlag; 
} packet_t; 

然後,您可以創建你不同的編譯根據您正在爲使用預處理宏系統的類型的函數。

如:

/* Uncomment the line below if you are using a little endian system; 
/* otherwise, leave it commented 
*/ 
//#define LITTLE_ENDIAN_SYSTEM 

// Function protocol 
void writeCommand(int cmd); 


//Function definition 
void writeCommand(int cmd, packet_t* pkt) 
{ 
    if(!pkt) 
    { 
    printf("Error, invalid pointer!"); 
    return; 
    } 

    #if LITTLE_ENDIAN_SYSTEM 
    pkt->commandMSB = (cmd && 0xFF00) >> 8; 
    pkt->commandLSB = (cmd && 0x00FF); 
    # else // Big Endian system 
    pkt->commandMSB = (cmd && 0x00FF); 
    pkt->commandLSB = (cmd && 0xFF00) >> 8; 
    #endif 

    // Done 
} 

int main void() 
{ 
    packet_t myPacket = {0}; //Initialize so it is zeroed out 
    writeCommand(0x1234,&myPacket); 


    return 0; 
} 

最後要注意:避免發送結構的數據流,發送給它的單個元素之一,在-A-時間,而不是!即:在這種情況下,不要假設結構在內部存儲,就像一大堆未簽名的字符。有些東西是編譯器和系統像打包和分配一樣放置的,結構實際上可能大於9 x sizeof(unsigned char)

祝你好運!

+0

非常感謝。這是對我的困惑的一個非常詳細的闡釋,隨後對我的下一個邏輯問題做出了很好的回答。 – ldg

+0

沒問題。在你的學習中祝你好運! – DevNull

1

這取決於架構,具體取決於您定位的處理器。有一種稱爲「Big Endian」的系統,它首先存儲一個字的最高有效字節,而「Little Endian」系統則首先存儲最低有效字節。看起來你正在看那裏的Little Endian系統。