字节序类型
以下类型的字节序有什么区别?
- 字节(8b)不变的大小字节序
- 半字(16b)不变大尾数
- 字(32b)不变大尾数
- 双字(64b)不变大和小的字节序
还有其他类型/变体吗?
解决方案
回答
基本概念是位的排序:
1010 0011
在little-endian中与
0011 1010
在big-endian中(反之亦然)。
我们会注意到排序是通过分组而不是单个位进行的。我不知道一个系统,例如
1100 0101
将是第一个版本的"其他字节序"版本。
回答
也有中间或者混合字节序。有关详细信息,请参见Wikipedia。
我唯一需要担心的是在C语言中编写一些网络代码时。网络通常使用大端IIRC。大多数语言或者抽象整个内容,或者提供库以确保我们使用的是正确的字节序。
回答
实际上,我将机器的字节序描述为单词中字节的顺序,而不是位的顺序。
这里的"字节"是指"架构可以单独管理的最小内存单元"。因此,如果最小单位为16位长(在x86中称为字),则可以像这样存储代表值0xFFFF0000的32位"字":
FFFF 0000
或者这个:
0000 FFFF
在内存中,取决于字节顺序。
因此,如果我们具有8位字节序,则意味着由16位组成的每个单词都将存储为:
FF 00
或者:
00 FF
等等。
回答
我读过的有关字节序的最佳文章"了解字节序和字节序"。
回答
字节序映射有两种方法:地址不变性和数据不变性。
地址不变性
在这种类型的映射中,字节的地址始终在大和小之间保留。这具有使特定数据(例如2或者4字节字)的有效顺序(最高有效到最低有效)颠倒的副作用,并因此颠倒了数据的解释。具体而言,在小字节序中,数据的解释对最重要的字节是最低有效的,而在大字节序中,数据的解释是对最低有效的最高。在这两种情况下,访问的字节集保持不变。
例子
地址不变性(也称为字节不变性):字节地址是恒定的,但字节的重要性相反。
Addr Memory 7 0 | | (LE) (BE) |----| +0 | aa | lsb msb |----| +1 | bb | : : |----| +2 | cc | : : |----| +3 | dd | msb lsb |----| | | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0xaa (preserved) Read 2 bytes: 0xbbaa 0xaabb Read 4 bytes: 0xddccbbaa 0xaabbccdd
数据不变性
在这种类型的映射中,相对字节的重要性被保留用于特定大小的数据。因此,对于不同的数据大小,存在不同类型的数据不变字节序映射。例如,将32位字不变字节序映射用于数据大小为32的情况。保留特定大小的数据值的效果是,数据字节的字节地址在大字节序和小字节序映射之间反转。
例子
32位数据不变性(也称为单词不变性):数据是一个32位单词,其值始终为0xddccbbaa,与字节序无关。但是,对于小于一个字的访问,字节的地址在大端和小端映射之间反转。
Addr Memory | +3 +2 +1 +0 | <- LE |-------------------| +0 msb | dd | cc | bb | aa | lsb |-------------------| +4 msb | 99 | 88 | 77 | 66 | lsb |-------------------| BE -> | +0 +1 +2 +3 | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0xdd Read 2 bytes: 0xbbaa 0xddcc Read 4 bytes: 0xddccbbaa 0xddccbbaa (preserved) Read 8 bytes: 0x99887766ddccbbaa 0x99887766ddccbbaa (preserved)
例子
16位数据不变性(也称为半字不变性):数据为16位
始终具有值" 0xbbaa",与字节序无关。但是,对于小于半字的访问,字节的地址在大端和小端映射之间反转。
Addr Memory | +1 +0 | <- LE |---------| +0 msb | bb | aa | lsb |---------| +2 msb | dd | cc | lsb |---------| +4 msb | 77 | 66 | lsb |---------| +6 msb | 99 | 88 | lsb |---------| BE -> | +0 +1 | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0xbb Read 2 bytes: 0xbbaa 0xbbaa (preserved) Read 4 bytes: 0xddccbbaa 0xddccbbaa (preserved) Read 8 bytes: 0x99887766ddccbbaa 0x99887766ddccbbaa (preserved)
例子
64位数据不变性(也称为双字不变性):数据为64位
始终具有值" 0x99887766ddccbbaa"的字,与字节序无关。但是,对于小于双字的访问,字节的地址在大端和小端映射之间反转。
Addr Memory | +7 +6 +5 +4 +3 +2 +1 +0 | <- LE |---------------------------------------| +0 msb | 99 | 88 | 77 | 66 | dd | cc | bb | aa | lsb |---------------------------------------| BE -> | +0 +1 +2 +3 +4 +5 +6 +7 | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0x99 Read 2 bytes: 0xbbaa 0x9988 Read 4 bytes: 0xddccbbaa 0x99887766 Read 8 bytes: 0x99887766ddccbbaa 0x99887766ddccbbaa (preserved)
回答
实际上,字节序是指处理器将解释给定存储位置的内容的方式。例如,如果我们具有以下内容(十六进制字节)的内存位置0x100
0x100: 12 34 56 78 90 ab cd ef Reads Little Endian Big Endian 8-bit: 12 12 16-bit: 34 12 12 34 32-bit: 78 56 34 12 12 34 56 78 64-bit: ef cd ab 90 78 56 34 12 12 34 56 78 90 ab cd ef
需要注意耐力性的两种情况是使用网络代码以及是否使用指针进行强制转换。
TCP / IP指定线路上的数据应为大端字节序。如果传输字节数组以外的其他类型(如指向结构的指针),则应确保使用ntoh / hton宏来确保数据以大端序发送。如果从小端处理器发送到大端处理器(反之亦然),则数据将出现乱码...
投放问题:
uint32_t* lptr = 0x100; uint16_t data; *lptr = 0x0000FFFF data = *((uint16_t*)lptr);
数据的价值是什么?
在大端系统上,该值为0;在小端系统上,该值为FFFF
回答
13年前,我研究了可同时用于DEC ALPHA系统和PC的工具。在该DEC ALPHA上,位实际上已反转。那是:
1010 0011
实际翻译成
1100 0101
在C代码中,它几乎是透明且无缝的,除了我声明了一个
typedef struct { int firstbit:1; int middlebits:10; int lastbits:21; };
需要翻译的内容(使用#ifdef条件编译)
typedef struct { int lastbits:21; int middlebits:10; int firstbit:1; };
回答
菲利伯特说,
bits were actually inverted
我怀疑任何体系结构都会破坏字节值不变性。当将包含位字段的结构映射到数据时,可能需要反转位字段的顺序。这种直接映射依赖于C99标准之外的编译器详细信息,但仍然可能很常见。直接映射速度更快,但不符合C99标准,该标准没有规定打包,对齐和字节顺序。符合C99的代码应基于值而不是地址使用慢速映射。也就是说,除了这样做,
#if LITTLE_ENDIAN struct breakdown_t { int least_significant_bit: 1; int middle_bits: 10; int most_significant_bits: 21; }; #elif BIG_ENDIAN struct breakdown_t { int most_significant_bits: 21; int middle_bits: 10; int least_significant_bit: 1; }; #else #error Huh #endif uint32_t data = ...; struct breakdown_t *b = (struct breakdown_t *)&data;
一个人应该写这个(这就是即使上面的"直接映射",编译器仍然会生成代码的方式),
uint32_t data = ...; uint32_t least_significant_bit = data & 0x00000001; uint32_t middle_bits = (data >> 1) & 0x000003FF; uint32_t most_significant_bits = (data >> 11) & 0x001fffff;
需要反转每个与字节序无关的,特定于应用程序的数据存储单元中位字段顺序的原因是,编译器将位字段打包为增长地址的字节。
每个字节中的"位顺序"无关紧要,因为提取它们的唯一方法是应用值掩码并转移到最低有效位或者最高有效位方向。 "位的顺序"问题仅在具有位地址概念的虚构体系结构中才变得重要。我相信所有现有的体系结构都将这一概念隐藏在硬件中,并且仅提供最低有效位提取还是最高有效位提取,这是基于字节序中性字节值的概念。