大小端及字節(jié)序在嵌入式軟件開發(fā)過程中經(jīng)常會(huì)遇到,數(shù)據(jù)傳輸、存儲(chǔ)、通信等這些地方都會(huì)牽涉到,下面就來(lái)給大家分享一下相關(guān)知識(shí)。
回顧字節(jié)序
字節(jié)序,即字節(jié)在電腦中存放時(shí)的序列與輸入(輸出)時(shí)的序列是先到的在前還是后到的在前。
---來(lái)自百度百科
拿數(shù)據(jù) 0x01020304為例:
在大端CPU中:數(shù)據(jù)將存儲(chǔ)為0x01(address + 0),0x02(address + 1),0x03(address + 2),0x04(address + 3)。
在小端CPU中:數(shù)據(jù)將存儲(chǔ)為0x04(address + 0),0x03(address + 1),0x02(address + 2),0x01(address + 3)。
如果你的程序使用簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)(例如“ int”和“ short”),則沒有什么麻煩。但是,如果數(shù)據(jù)結(jié)構(gòu)類似于以下示例,則可能會(huì)遇到問題。
union { unsigned int dat; unsigned char c[4]; }X; void foo( ) { int t0; X.dat = 0x01020304; t0 = X.c[0]; ??? }
在大端 CPU 中編譯并執(zhí)行此代碼時(shí), t0”的值為0x01。在小端CPU中, t0”的值為0x04。
那么問題來(lái)了:要想使存儲(chǔ)順序從大端,變?yōu)樾《?,怎么辦呢?
方法其實(shí)有很多種,這里講講針對(duì)IAR的兩種方法:
使用__big_endian關(guān)鍵字。
使用__REV, __REV16, __REVSH, RBIT函數(shù)。
使用__big_endian關(guān)鍵字
IAR中__big_endian關(guān)鍵字提供了一種方便的方式來(lái)將應(yīng)用程序從big-endian移植到little-endian。
__big_endian關(guān)鍵字用于訪問以big-endian字節(jié)順序存儲(chǔ)的變量,而與應(yīng)用程序其余部分使用的字節(jié)順序無(wú)關(guān)。在ARMv6或更高版本進(jìn)行編譯時(shí),可以使用__big_endian關(guān)鍵字。
只需添加__big_endian關(guān)鍵字即可,如:
____big_endian union { unsigned int dat; unsigned char c[4]; }X; void foo( ) { int t0; X.dat = 0x01020304; t0 = X.c[0]; ??? }
修改后的代碼在低位字節(jié)CPU中編譯和執(zhí)行,變量“ t0”為0x01。
注意:此關(guān)鍵字不能用于指針。同樣,此屬性不能在數(shù)組上使用。
同時(shí),關(guān)鍵字__big_endian插入REV指令以交換字節(jié)數(shù)據(jù),REV指令的插入會(huì)影響代碼大小和執(zhí)行時(shí)間。
關(guān)鍵字具有限制,不能應(yīng)用于復(fù)雜的數(shù)據(jù)結(jié)構(gòu),比如以下代碼會(huì)生成錯(cuò)誤:
__big_endian union { unsigned long dat; unsigned char c[4]; struct { unsigned long a0: 1; unsigned long a1: 1; unsigned long a2: 2; unsigned long a3: 4; unsigned long a4: 8; unsigned long a5: 16; }s; } f1_dat2;
使用__REV, __REV16, __REVSH, RBIT函數(shù)
大端和小端之間的字節(jié)順序差異只是順序,因此我們需要做的是更改字節(jié)順序,我們?cè)俅我宰兞?x01020304為例:
我們可以通過代碼實(shí)現(xiàn)交換功能,比如:
typedef unsigned long uint32_t; uint32_t bswap_32(uint32_t x) { uint32_t t = x; uint32_t s; s = ( (((uint32_t)(t) (uint32_t)0x000000ffUL) << 24) | (((uint32_t)(t) (uint32_t)0x0000ff00UL) << 8) | (((uint32_t)(t) (uint32_t)0x00ff0000UL) >> 8) | (((uint32_t)(t) (uint32_t)0xff000000UL) >> 24) ); return s; }
通過這種方式實(shí)現(xiàn),將導(dǎo)致消耗更多時(shí)間和代碼大小。
在C代碼中,我們通常編寫內(nèi)聯(lián)匯編代碼實(shí)現(xiàn)交換。IAR有種內(nèi)部函數(shù)可以實(shí)現(xiàn)該功能。
比如下面交換功能:
代碼如下:
#include void x1( void ) { s2 = __REV(s1); s3 = __REV16(s1); s4 = __REVSH(s1); }
以上就是在IAR中實(shí)現(xiàn)大小端字節(jié)序的遷移方法,感興趣的讀者可以在IAR中編碼測(cè)試一下。
來(lái)源:嵌入式專欄
審核編輯:湯梓紅
-
單片機(jī)
+關(guān)注
關(guān)注
6067文章
44992瀏覽量
650630 -
嵌入式
+關(guān)注
關(guān)注
5152文章
19675瀏覽量
317691 -
cpu
+關(guān)注
關(guān)注
68文章
11080瀏覽量
217133
發(fā)布評(píng)論請(qǐng)先 登錄
制作單片機(jī)的幾點(diǎn)心得體會(huì)

單片機(jī)大小端數(shù)據(jù)處理問題
單片機(jī)學(xué)習(xí)的意義有哪幾點(diǎn)呢
單片機(jī)ad轉(zhuǎn)換電路

單片機(jī)EMC設(shè)計(jì)的幾點(diǎn)建議

單片機(jī)EMC設(shè)計(jì)的幾點(diǎn)建議

單片機(jī)實(shí)驗(yàn)-- AD轉(zhuǎn)換實(shí)驗(yàn)
單片機(jī)C語(yǔ)言的幾點(diǎn)基礎(chǔ)知識(shí)說明

51單片機(jī)的IO接口的地址和賦值大小的關(guān)系

ARM大小端模式

評(píng)論