关于Endian的问题,脑袋想破了。

SnHnBn 2003-08-27 04:38:57
请各位大侠帮忙考虑以下问题:
假设一种CPU支持Big-Endian和Little-Endian两种字节序,那么:
1、在Big-Endian字节序和Little-Endian字节序两种方式下,读取32-bit数据,CPU的数据总线读到的东西是否要作不同的转换放入寄存器当中?
2、驱动在读写一个已知硬件的32bit寄存器时,是否要考虑CPU或总线控制器的Endian模式?为什么?
...全文
163 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
SnHnBn 2003-08-29
  • 打赏
  • 举报
回复
longxiaozhou(阿龙),便宜你了:)
SnHnBn 2003-08-29
  • 打赏
  • 举报
回复
得了,在另外一个论坛得到了答案,基本上和我这两天查资料,思考的一致,我是走了弯路。
看来,搞嵌入式的还是去专业论坛的好。
http://www.embed.com.cn

嵌入开发技术论坛

讨论区:处理器专栏 论坛首页

--------------------------------------------------------------------------------
主题:Re:关于Endian的问题,脑袋想破了。 <--- 〖回复该帖子〗

一般来说,对两种endian的支持不是动态的,就是说对于一个具体的应用,应该是考虑实际用到的那一种就可以了。
1、在Big-Endian字节序和Little-Endian字节序两种方式下,读取32-bit数据,CPU的数据总线读到的东西是否要作不同的转换放入寄存器当中?

如果是字对齐的地址,就不用转换,如果不是,就要转换,而且两种字节顺序要分开考虑。
2、驱动在读写一个已知硬件的32bit寄存器时,是否要考虑CPU或总线控制器的Endian模式?为什么?
同上,如果是32位操作,而且是字对齐地址,就不用考虑,如果不是,就要考虑两种情况。两种字节顺序,可以通过程序判断出来。就是说,程序执行的时候判断一下,可以根据不同结果作相应的处理。
※ 作 者: 清风徐来 2003-8-28 13:15:59 ※
longxiaozhou 2003-08-28
  • 打赏
  • 举报
回复
熟悉x86汇编的人立刻就知道这个值应为0x3412,很对,但在一些情况下,比如说你在SGI的机器上看到这种情况,则正好相反,0x1234才是正确答案,这与CPU内部处理数据的方式有关。这两种处理方式都存在于不同厂商生产的CPU之中,在上例中若此WORD值为0x3412的,我们称之为little-endian, 若为0x1234的,我们称之为big-endian,这是两种不同的byte orders。MSDN中有比较精确的定义如下:

Byte Ordering Byte ordering Meaning
big-endian The most significant byte is on the left end of a word.
little-endian The most significant byte is on the right end of a word.

一般来说我们不用关心byte ordering的问题,但若要涉及跨平台之间的通信和资源共享,则不得不考虑这个问题了。也许你会说,我永远不会去用其它非x86的CPU,也许是这样,你甚至可以不必知道我们最常用的Intel,AMD等生产的x86的byte ordering是little-endian的,而且按现在的装机数量来看,可以说世界上绝大多数CPU是little-endian的,但多了解一些没有什么坏处,也许有用上的一天,实际若您要涉及到网络编程,了解一些还是有所帮助的,看完本文后您就应该知道为何socket编程中为何要用到如 ntohl, htonl, ntohs, htons这几个看起来名字似乎怪怪的API了,也很容易理解这些函数名的意义了。

假设我们要在不同byte ordering的机器之间传输和交换数据,那该怎么办呢,有两个方法,一是全部转换成文本来传输(如XML使用的),另一个方法两方都按照某一方的byte order,这时就涉及到了不同byte order之间相互转换的问题(网络传输标准如TCP/IP采用第二种方法并且由于历史的原因,byte ordering是big-endian的)。两种之间该如何转换呢?方法有很多,我们可以先看看MFC中在处理serialize的代码中所用的方法(List), 虽然代码应该是高效易读的, 但我个人并不喜欢它, 原因是我觉得这不是一种通用优美的方法.下面列出的是我自己写的转换的代码:


template
F3D_INLINE T ConvertEndian(T t)
{
T tResult = 0;
for (int I = 0; I < sizeof(T); ++ I)
{
tResult <<= 8;
tResult |= (t & 0xFF) ;

t >>= 8;
}

return tResult;
}

原理非常简单,交换字节顺序,我就不多说了,当然这个写法并不是快速的, 只是通用的(我没条件试, 若有不对之处请指出), 若要快速的代码,可以在不同platform上用与platform相关的代码, 如在PowerPC上有 "load word byte-reversed indexed" (lwbrx) 和 "load halfword byte-reversed indexed" (lhbrx) 指令, 在x86上还可用BSWAP单个汇编指令等,在类型上专为int16, int32写的通用的代码也可以比这快得多.

当然如果在byte ordering相同的情况下,应该不必用这个转换函数,所以我们可以定义一个宏来处理不同的byte ordering,也可以在运行时测试byte ordering, 下面的代码给出了一个简单的测试方法。


// Test for endianness.
F3D_INLINE bool IsLittleEndian(void)
{
DWORD dwTestValue = 0x12345678L;
return (*((BYTE*)&dwTestValue) == 0x78);
}

但是float比较怪,有可能所涉及到不仅仅是byte order的问题,因为有些平台如Alpha不使用IEEE的浮点格式,还得自己转换。当然同上,其它的方法一是将所用的float用文本方式输入输出,另一个办法是在某些情况下可将其转换成定点数再处理,这里我不再深入。

如果是读写第三方已经指定byte order的文件或数据流,比如说读SGI的位图文件格式,则可以直接自行按指定的byte order拼起来,不必考虑host机是何种byte ordering。下面我给出相应的代码:


// Read a little-endian TYPE from address
template
F3D_INLINE T GetLittleEndian(const BYTE* pBuf)
{
T tResult = 0;
pBuf += sizeof(T) - 1;
for (int I = 0; I < sizeof(T); ++ I)
{
tResult <<= 8;
tResult |= *pBuf --;
}

return tResult;
}

// Read a big-endian TYPE from address
template
F3D_INLINE T GetBigEndian(const BYTE* pBuf)
{
T tResult = 0;
for (int I = 0; I < sizeof(T); ++ I)
{
tResult <<= 8;
tResult |= *pBuf ++;
}

return tResult;
}

// Set a little-endian TYPE on a address
template
F3D_INLINE void SetLittleEndian(BYTE* pBuf, T t)
{
for (int I = 0; I < sizeof(T); ++ I)
{
*pBuf ++ = BYTE(t & 0xFF);
t >>= 8;
}
}

// Set a big-endian T on a address
template
F3D_INLINE void SetBigEndian(BYTE* pBuf, T t)
{
pBuf += sizeof(T) - 1;
for (int I = 0; I < sizeof(T); ++ I)
{
*pBuf -- = BYTE(t & 0xFF);
t >>= 8;
}
}

从上文可以看出,byte order挺简单的,一般应用中可能也用不上,但若您对写跨平台的程序有兴趣,则一定要了解的比较清楚才行。以上代码都是从实际使用的源码中取下来的。

附:常见Processor, OS的byte ordering情况

Processor OS Order
x86 (Intel, AMD, … ) All little-endian
DEC Alpha All little-endian
HP-PA NT little-endian
HP-PA UNIX big-endian
SUN SPARC All? big-endian
MIPS NT little-endian
MIPS UNIX big-endian
PowerPC NT little-endian
PowerPC non-NT big-endian
RS/6000 UNIX big-endian
Motorola m68k All big-endian
SnHnBn 2003-08-28
  • 打赏
  • 举报
回复
分可以加,我现在有5000多分,想要多少可以提,能给点意见的,有一点作用的话我也会给分的。有不明白的可以问清楚。高手在哪里?
SnHnBn 2003-08-28
  • 打赏
  • 举报
回复
这篇文章好像我在网上看过,Endian的基本知识我懂,只是好像对我的问题没什么作用。不过还是打算给一点分。
分不够我可以另外开个贴子加,还请各位多多帮忙。

21,597

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧