tcp报文收发时, data offset 的ushort是否需要做字节序转换?
如下的黑体部分0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Data | |U|A|P|R|S|F | |
| Offset | Res |R|C|S|S|Y |I | Window |
| | |G|K|H|T|N |N | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
struct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else 回复 1# mordorwww
就 4 个 bit,不需要转换的。直接用。字节序,是超过一个 byte 时需要考虑的。
Godbach 发表于 2016-06-22 18:19 static/image/common/back.gif
回复 1# mordorwww
就 4 个 bit,不需要转换的。直接用。字节序,是超过一个 byte 时需要考虑的。
我是问她所在的这个 ___u16不用转换吧 回复 3# mordorwww
所在的 _u16 已经按照 bitfield 分出去了,你直接通过结构体对应的各自成员去访问就成了。你没有必要一下子读取整个 _u16 的值啊,或者是这个 _u16 的数值对你来说没有用处。
只有你需要一次读取超过 1 个 bytes 的数值时,才需要考虑字节序的转换。 本帖最后由 mordorwww 于 2016-06-23 11:45 编辑
Godbach 发表于 2016-06-23 10:47 static/image/common/back.gif
回复 3# mordorwww
所在的 _u16 已经按照 bitfield 分出去了,你直接通过结构体对应的各自成员去访问就 ...
下面这种奇葩的定义见过没
我觉得应该是要对整个64bits做字节序转换,虽然位域没有超过或者达到8bits,但是好几个都跨bytes甚至跨short了。手头上没有big的CPU,没法验证
#if __BYTE_ORDER != __LITTLE_ENDIAN
uint32_t Odo:32;
uint16_t BmprHghtFnt:7;
uint16_t BmprHghtRear:7;
uint16_t VehHght:7;
uint16_t VehMass:7;
uint16_t VehType:4;
#else// __BYTE_ORDER != __BIG_ENDIAN
uint16_t VehType:4;
uint16_t VehMass:7;
uint16_t VehHght:7;
uint16_t BmprHghtRear:7;
uint16_t BmprHghtFnt:7;
uint32_t Odo:32;
#endif 回复 5# mordorwww
那你把数字反着写不能验证么? 那你把数字反着写不能验证么? 回复 5# mordorwww
这个人家结构体定义的时候已经考虑好了。你就按照单个成员访问就行了。超过一个字节的,要考虑这个问题。
本帖最后由 karma303 于 2016-06-26 09:27 编辑
结构体内bitfield的顺序是对byte endian敏感的。
并不是说x86或MIPS除了byte order之外,还有bit order的区别。
这个问题的根源在于编译器。纯粹是编译器作怪。展开讲话就多了。暂且不表。
不过我可以告诉你一个技巧,如果位域不跨字节的,大小端的变换是有规律的。
像小端模式的一个结构体:
struct abcdef {
int a: 4;
int b: 4;
int c: 4;
int d: 2;
int e: 2;
};
你想让它在MIPS上的gcc编译后有同样的内存布局,方法是:从上到下,位域每8个bit一组,反转组内的成员顺序。结果是这样:
struct abcdef {
int b: 4;
int a: 4;
int e: 2;
int d: 2;
int c: 4;
};
如果位域跨字节,那我就没有办法了。你贴出来的那个struct video什么的代码,我是看不懂的。
一般这种针对big/little endian的条件编译,是出于两种场合的需要。
(1)网络底层协议的传输,从host A传到 host B上,相当于一份远程的内存拷贝,网络协议必须规定这段内存(记作xxx)该以big or little endian的方式存放数据。 我们上面代码里#if #else条件编译,其实都是折腾编译器。我们希望我们的代码在MIPS和x86机器编译后,希望类似下面的代码的输出是一致的:
----------------------------------------------
struct tcphdr *hdr = (void *)xxx;
printf( "%d\n", hdr->res1);
---------------------------------------------
(2) 驱动代码里,我们要把bitfield与寄存器对应死。
自己写的一篇帖子,希望对题主有帮助。http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4248004&extra=
页:
[1]