关于单字节的字节序的问题
一直认为 Big_endian, Little_endian 只有在多字节的数据中才有意义.
今天看 linux 网络部分的代码 关于 ip头 的定义如下:
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
很纳闷啊, 单字节的数据也有字节序的问题?
我在 little 下是 0x12, 难道在 big 下是 0x21
我做了个实验, 将 0x1234 用二进制打印出来:
00110100 00010010 -- 0x34 0x12
然后将 0x1234 htons 以后 再打印出来:
00010010 00110100 -- 0x12 0x34
很显然 单字节并没有因为字节序的不同而不同, 那他原代码中为什么会如此写呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一个是机器的endian,一个是网络的endian。
说字节序只在多字节时才有意义是因为我们多数时候是使用2字节或4字节值,bit序也是有的,但CPU和网络之间会自动处理,所以编程时不关心。但IP头部的值并不都是字节的整数倍,这样的话就要考虑了。
你打印的话当然是看不出区别的,因为指令中已经自动处理了。你可以分别在Big-endian和Little-endian的计算机上用位域试一试,能看出区别来。以前做网络程序时经常要避免位域,就是比较容易出错。
[ 本帖最后由 Cyberman.Wu 于 2009-7-14 16:58 编辑 ]
这个问题有时候挺让人郁闷的,其实关键在于一个标准如何统一的问题,因为大端小端已是无法逃避的问题了。
根据C语言标准里,“An implementation may allocate any addressable storage unit large enough to hold a bitfield.
If enough space remains, a bit-field that immediately follows another bit-field in a
structure shall be packed into adjacent bits of the same unit.”
关键什么叫相邻?
我们还是用硬件描述语言的思路去理解这个问题吧。
其实大端和小端并不是天壤之别,拓扑来看,不过是某些接线顺序的问题,
比如verilog,命一个16bit的wire,你会怎么命?
wire [15:0] sample;
还是
wire [0:15] sample;
无论怎么命吧,
assign sample = 16'h1234;
在两种形式下,sample的每个bit将会是什么?
于是我们再考虑,按照两种方式设计的硬件(假设上面的那个是大端,下面这个的是小端)
这个sample直接接1个16bit的ram的数据总线。
那么
struct {
unsigned char a;
unsigned char b:4;
unsigned char c:4;
} x;
这个x此时从数据总线里出来,假设就是前面的那个16'h1234,
小端的时候,
x.a代表sample[8:0],自然是0x34
s.b因为是相邻,所以代表sample[12:9],自然是0x2
s.c代表sample[16:13],自然是0x1
而大端的时候,
x.a代表sample[0:8],自然是0x12
s.b因为是相邻,所以代表sample[9:12],自然是0x3
s.c代表sample[16:13],自然是0x4
数字设计的时候我经常被这些东西搞晕掉。
复制代码
恩,知道原因了,这里的x应该是4个字节。k.b是不能跨两个unsigned char的。
[ 本帖最后由 cjaizss 于 2009-7-15 22:09 编辑 ]