從大端CPU遷移到小端CPU,及字節(jié)序的遷移技術
素材來源:網(wǎng)絡
編輯整理:strongerHuang
之前給大家分享過大小端的一些內(nèi)容,閱讀本文之前可以再次回顧一下:
CPU大小端模式嗎?" tab="innerlink" data-linktype="2" rel="nofollow">你真的懂CPU大小端模式嗎?
一、回顧字節(jié)序
拿數(shù)據(jù) 0x01020304為例:
在大端CPU中:數(shù)據(jù)將存儲為0x01(address + 0),0x02(address + 1),0x03(address + 2),0x04(address + 3)。
在小端CPU中:數(shù)據(jù)將存儲為0x04(address + 0),0x03(address + 1),0x02(address + 2),0x01(address + 3)。
如果你的程序使用簡單的數(shù)據(jù)結(jié)構(gòu)(例如“ int”和“ short”),則沒有什么麻煩。但是,如果數(shù)據(jù)結(jié)構(gòu)類似于以下示例,則可能會遇到問題。
union {
unsigned int dat;
unsigned char c[4];
}X;
void foo( ) {
int t0;
X.dat = 0x01020304;
t0 = X.c[0];
???
}
在大端 CPU 中編譯并執(zhí)行此代碼時, t0”的值為0x01。在小端CPU中, t0”的值為0x04。
那么問題來了:要想使存儲順序從大端,變?yōu)樾《?,怎么辦呢?
方法其實有很多種,這里講講針對IAR的兩種方法:
使用__big_endian關鍵字。
使用__REV, __REV16, __REVSH, RBIT函數(shù)。
二、使用__big_endian關鍵字
IAR中__big_endian關鍵字提供了一種方便的方式來將應用程序從big-endian移植到little-endian。
__big_endian關鍵字用于訪問以big-endian字節(jié)順序存儲的變量,而與應用程序其余部分使用的字節(jié)順序無關。在ARMv6或更高版本進行編譯時,可以使用__big_endian關鍵字。
只需添加__big_endian關鍵字即可,如:
____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。
注意:此關鍵字不能用于指針。同樣,此屬性不能在數(shù)組上使用。
同時,關鍵字__big_endian插入REV指令以交換字節(jié)數(shù)據(jù),REV指令的插入會影響代碼大小和執(zhí)行時間。
關鍵字具有限制,不能應用于復雜的數(shù)據(jù)結(jié)構(gòu),比如以下代碼會生成錯誤:
__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é)順序,我們再次以變量0x01020304為例:
我們可以通過代碼實現(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;
}
#include <intrinsics.h>
void x1( void ) {
s2 = __REV(s1);
s3 = __REV16(s1);
s4 = __REVSH(s1);
}
當然,具體的使用以及細節(jié)內(nèi)容,需要看查看官方說明。
免責聲明: 本文素材來源網(wǎng)絡,版權(quán)歸原作者所有。如涉及作品版權(quán)問題,請與我聯(lián)系刪除。 推薦閱讀: IAR進軍Linux,支持在Linux搭建編譯環(huán)境 Linux 為何會流行?它和普通的RTOS有何區(qū)別? Windows Terminal 1.0 和 Linux 版有啥區(qū)別
關注 微信公眾號『strongerHuang』,后臺回復“1024”查看更多內(nèi)容,回復“加群”按規(guī)則加入技術交流群。
長按前往圖中包含的公眾號關注
免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!