大小端及字節(jié)序在嵌入式軟件開(kāi)發(fā)過(guò)程中經(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”),則沒(méi)有什么麻煩。但是,如果數(shù)據(jù)結(jié)構(gòu)類(lèi)似于以下示例,則可能會(huì)遇到問(wèn)題。
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。
那么問(wèn)題來(lái)了:要想使存儲(chǔ)順序從大端,變?yōu)樾《耍趺崔k呢?
方法其實(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)鍵字用于訪問(wè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為例:
我們可以通過(guò)代碼實(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; }
通過(guò)這種方式實(shí)現(xiàn),將導(dǎo)致消耗更多時(shí)間和代碼大小。
在C代碼中,我們通常編寫(xiě)內(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)源:嵌入式專(zhuān)欄
審核編輯:湯梓紅
-
單片機(jī)
+關(guān)注
關(guān)注
6043文章
44621瀏覽量
638559 -
嵌入式
+關(guān)注
關(guān)注
5092文章
19177瀏覽量
307674 -
cpu
+關(guān)注
關(guān)注
68文章
10902瀏覽量
213016
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論