karma303 发表于 2016-07-06 17:17

biefield与endian 2

本帖最后由 karma303 于 2016-07-06 17:19 编辑

本来想更新到这篇旧帖子里的,但觉得这部分有点儿“地理大发现”的感觉,就专门贴出来,跟各位交流。
我说的“地理大发现”,是说wiki上的ip header的布局图,它们用0,1,2,3,4,5,6,7细分出每个字节的bit,但wiki上的0,1,2,3,4,5,6,7,分别对应常规思维的7,6,5,4,3,2,1,0。


   到这里我才发现,原来wiki上给出的布局图,是彻彻底底的按照“大端思维“来走的。
   其实wiki就从RFC里摘的图,1981年的文档,那时的程序员为什么会反着看bit?(是没经过x86的洗礼吗?)
   
   题外话:
   在上一篇帖子里,我贴了一点关于bitfield跨字节的测试。
   其实今天意识到这个问题,也是从ip header里的offset成员开始的,我发现没办法用bitfield来表示这个成员。


如果编译目标是小端机器,gcc是没有办法用bitfield来表示offset这个成员的。
所以linux内核里,很粗暴的定义成:
__be16        frag_off;
__be16就是unsigned short。
然后在代码里再分解它:
        offset = ntohs(ip_hdr(skb)->frag_off);
        flags = offset & ~IP_OFFSET;
        offset &= IP_OFFSET;
        offset <<= 3;                /* offset is in 8-byte chunks */

Godbach 发表于 2016-07-06 19:43

回复 1# karma303

佩服 LZ 深度钻研的精神!

   

Godbach 发表于 2016-07-06 19:48

回复 1# karma303
最后一个图,太能说明问题了。{:qq11:}


   

mordorwww 发表于 2016-07-07 15:32

karma303 发表于 2016-07-06 17:17 static/image/common/back.gif
本来想更新到这篇旧帖子里的,但觉得这部分有点儿“地理大发现”的感觉,就专门贴出来,跟各位交流。
   ...

在部分平台或许可以,linux要用在各种CPU平台上,所以这样了

nswcfd 发表于 2016-07-07 17:03

本帖最后由 nswcfd 于 2016-07-07 17:04 编辑

精彩的分析!

对于线上的bit,估计是先到的算0号吧?

karma303 发表于 2016-07-07 17:44

回复 5# nswcfd



   网线按什么样的bit序传递数据,似乎影响不到软件编程。连写网卡驱动时都不需要关心它。
   我在osdev上问过相关的问题,但得到的回答有不痛不痒,可能是我英文水平有限吧。
   forum.osdev.org/viewtopic.php?f=1&t=30485

nswcfd 发表于 2016-07-07 18:34

本帖最后由 nswcfd 于 2016-07-07 18:39 编辑

嗯,forum.osdev.org/viewtopic.php?f=1&t=30485,很有意思的讨论。

https://en.wikipedia.org/wiki/Bit_numbering
里面有一句话
The recommended style for Request for Comments documents is "MSB 0" bit numbering.

Scott, Gregor (June 1998 ). "RFC 2360 - Guide for Internet Standards Writers". Internet Engineering Task Force (IETF). p. 11. Retrieved 2010-02-14. The preferred form for packet diagrams is a sequence of long words in network byte order, with each word horizontal on the page and bit numbering at the top
"RFC 1166 - INTERNET NUMBERS". Internet Engineering Task Force (IETF). July 1990. p. 1. Retrieved 2014-06-11. Whenever an octet represents a numeric quantity the left most bit in the diagram is the high order or most significant bit

https://upload.wikimedia.org/wikipedia/commons/5/54/Msb0.svg

nswcfd 发表于 2016-07-07 19:10

本帖最后由 nswcfd 于 2016-07-07 19:31 编辑

struct BYTE {
char bit:1;
};

bitfield是C语言的概念,所以C编译器需要关心,BYTE.bit到底使用MSB还是使用LSB。
*选择LSB,BYTE.bit =1 对应 or 0x01;
*选择MSB,BYTE.bit = 1对应 or 0x80;
*选择其它bit应该也是可以的吧?

我的问题是,虽然x86上的gcc事实上选择了LSB(没说错吧?),
但是如果假设它选择了使用MSB,那有没有违反C标准的规定?或者会造成其它语义上的错误?

karma303 发表于 2016-07-07 20:36

回复 8# nswcfd

《程序员的自我修养》的附录A.1讲了byte order,不知道你看过没。
类似这样的句子,
Big-endian和little-endian的区别就是big-endian规定MSM在存储时放在低地址,在传输时MSB放在流的开始;LSB存储时放在高地址,在传输时放在流的末尾。little-endian则相反。
讲的很好。

但我几乎不关心LSB和MSB的概念,它只会让我困扰。
所以你的问题,都不在我的思维模式里,抱歉我一个答不上来。
   

karma303 发表于 2016-07-07 20:48

回复 4# mordorwww

对,像MIPS上,用bitfield访问就很自然。
这种东西,只要道理明白了,剩下的都事在人为。像我的内核(x86)里,照样的用bitfield访问:
struct iphdr{
        u32 len: 4;                                                /* header length */
        int version: 4;
        u8 ignore;
        u16 tot_len;                                        /* total length, header included */
        u16 msgid;                                                /* IP datagram identification */
        union{
                struct{
                        u16 me_offset: 13;                                /* the offset of this IP fragment */
                        int flag_mf: 1;                                        /* more fragments */
                        int flag_df: 1;                                        /* don't fragment */
                        int flag_reserved: 1;
                };
                u16 flag_off;
        };
        u8 ttl;
        u8 protocol;
        u16 chksum;
        u32 myip;
        u32 yourip;
};
每当接收到一个ip报文时,我先把flag_off成员字节翻转,然后就可以用bitfield访问了。
页: [1] 2
查看完整版本: biefield与endian 2