之前給大家分享過(guò)大小端的一些內(nèi)容,閱讀本文之前可以再次回顧一下:
CPU大小端模式嗎?" tab="innerlink" data-linktype="2" rel="nofollow">你真的懂CPU大小端模式嗎?
大小端格式由編譯器還是CPU決定的?
一、回顧字節(jié)序
拿數(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)樾《?,怎么辦呢?
方法其實(shí)有很多種,這里講講針對(duì)IAR的兩種方法:
二、使用__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)該功能。
void x1( void ) {
s2 = __REV(s1);
s3 = __REV16(s1);
s4 = __REVSH(s1);
}
當(dāng)然,具體的使用以及細(xì)節(jié)內(nèi)容,需要看查看官方說(shuō)明。
免責(zé)聲明:
本文素材來(lái)源網(wǎng)絡(luò),版權(quán)歸原作者所有。如涉及作品版權(quán)問(wèn)題,請(qǐng)與我聯(lián)系刪除。
關(guān)注
微信公眾號(hào)『strongerHuang』,后臺(tái)回復(fù)“1024”查看更多內(nèi)容,回復(fù)“加群”按規(guī)則加入技術(shù)交流群。
長(zhǎng)按前往圖中包含的公眾號(hào)關(guān)注