Big Endian和Little endian很少混淆

时间:2017-12-01 04:46:19

标签: c pointers endianness

我正在阅读此网站http://www.geeksforgeeks.org/little-and-big-endian-mystery/中的小端和大端代表。

假设我们有一个数字0x01234567,那么在little endian中它存储为(67)(45)(23)(01),在Big endian中它存储为(01)(23)(45)(67)

char *s= "ABCDEF"
int *p = (int *)s;
printf("%d",*(p+1)); // prints 17475 (value of DC)

在上面的代码中看到打印值后,似乎字符串存储为(BA)(DC)(FE)。

为什么不像第一个例子那样将(EF)(CD)(AB)从LSB存储到MSB?我认为endianess意味着在多字节内排序字节。那么排序应该是关于“整个2字节”,如第二种情况,而不是在那2个字节内吗?

4 个答案:

答案 0 :(得分:7)

使用2字节int,这就是你在内存中的内容

memAddr  |  0  |  1  |  2  |  3  |  4  |  5  |  6   |
data     | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | '\0' |
            ^ s points here
                        ^ p+1 points here

现在看起来你正在使用ASCII编码,所以这就是真正在内存中的含义

memAddr  |  0   |  1   |  2   |  3   |  4   |  5   |  6   |
data     | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x00 |
            ^ s points here
                          ^ p+1 points here

因此,对于一个小端机器,这意味着首先是多字节类型的最低有效字节。对于单个字节char,没有关于字节序的概念。 ASCII字符串只是char s的字符串..这没有endianess。你的int是2个字节。因此,对于从存储器位置2开始的int,该字节是最不重要的,而地址3处的字节是最重要的。这意味着这里的数字,读取人们通常读取数字的方式,是0x4443(基数10的17475,“DC”作为ASCII字符串),因为内存位置3中的0x44比内存位置2中的0x43更重要。对于大端当然,这将是相反的,数字将是0x4344(基数为10的17220,“CD”为ASCII字符串)。

编辑:

解决您的评论... c字符串是一个NUL终止的char数组,这绝对是正确的。 Endianess仅适用于原始类型short, int, long, long long等。(“原始类型”可能是不正确的命名法,知道的人可以纠正我)。数组只是连续内存的一部分,其中一种或多种类型直接相邻发生,按顺序存储 。整个数组没有endianess的概念,但是endianess 适用于数组的各个元素的基本类型。假设你有以下假设,假设有2个字节int s:

int array[3];  // with 2 byte ints, this occupies 6 contiguous bytes in memory
array[0] = 0x1234;
array[1] = 0x5678;
array[2] = 0x9abc;

这就是内存的样子:无论是大型还是小型机器,都会看起来像这样。

memAddr   |    0-1   |    2-3   |    4-5   |
data      | array[0] | array[1] | array[2] |

请注意,数组元素没有endianess的概念。无论元素是什么,都是如此。元素可以是原始类型,structs,任何东西。数组中的第一个元素始终位于array[0]

但现在,如果我们看一下阵列中的实际内容,这就是endianess发挥作用的地方。对于小端机器,内存将如下所示:

memAddr   |  0   |  1   |  2   |  3   |  4   |  5   |
data      | 0x34 | 0x12 | 0x78 | 0x56 | 0xbc | 0x9a |
             ^______^      ^______^      ^______^
             array[0]      array[1]      array[2]

最低有效字节是第一个。一个大端机器看起来像这样:

memAddr   |  0   |  1   |  2   |  3   |  4   |  5   |
data      | 0x12 | 0x34 | 0x56 | 0x78 | 0x9a | 0xbc |
             ^______^      ^______^      ^______^
             array[0]      array[1]      array[2]

请注意,数组中每个元素的内容都受到字节序的影响(因为它是一个基本类型的数组...如果它是structs的数组,{{1}成员不会受到某种类型的结束性逆转,但是结尾只适用于原语)。但是,无论是在大端还是小端机器上,数组元素的顺序仍然相同。

回到你的字符串,字符串只是一个struct终止的字符数组。 NUL是单个字节,因此只有一种方法可以对它们进行排序。考虑一下代码:

char

这就是你在记忆中所拥有的:

char word[] = "hey";

就这种情况而言,memAddr | 0 | 1 | 2 | 3 | data | word[0] | word[1] | word[2] | word[3] | equals NUL terminator '\0' ^ 数组的每个元素都是一个字节,并且只有一种方法可以订购单个项目,因此无论是在小型还是大型端机上,这都是您所需要的在记忆中:

word

Endianess仅适用于多字节基元类型。我强烈建议在调试器中查看,以便在实际操作中看到这一点。所有流行的IDE都有内存视图窗口,或者memAddr | 0 | 1 | 2 | 3 | data | 0x68 | 0x65 | 0x79 | 0x00 | 可以print out memory。在gdb中,您可以将内存打印为字节,半字(2字节),字(4字节),巨字(8字节)等。在小端机器上,如果您将字符串打印为字节,我会按顺序看到这些字母。打印成半字,你会看到每2个字母“反转”,打印出来的单词,每4个字母“反转”等。在大端机器上,它将以相同的“可读”顺序打印出来。 / p>

答案 1 :(得分:3)

字符串似乎有点混乱

1)  "ABCDEF"

和以十六进制表示的数字11,259,375是

2)  0xABCDEF

在第一种情况下,每个字母占一个字节 在第二种情况下,我们有六个十六进制数字;一个十六进制数字需要4位,因此一个字节需要两位数。

Endianness 明智的,如果是 1)字符' A'然后' B'等等。按顺序写入内存。 ' A'是0x41,' B' 0x42 ...如果是 2)这是一个多字节整数,字节顺序取决于体系结构。假设数字是4个字节,一个大端弧将存储在内存中(十六进制)00 AB CD EF; little-endian将按此顺序存储:EF CD AB 00

Big endian

A  B  C  D  E  F
41 42 43 44 45 46   [ text ]
00 AB CD EF         [ integer ] 
----(addresses)---->

Little endian

----(addresses)---->
A  B  C  D  E  F
41 42 43 44 45 46   [ text ]
EF CD AB 00         [ integer ]

在你的情况下

char *s= "ABCDEF";     // text
int *p = (int *)s;     //
printf("%d",*(p+1));   // *(p+1) is p[1]

由于您的实施具有sizeof(int) == 2,因此打印的数字(17475)为0x4443,或者' DC' (字符),0x44(' D')作为MSB,0x43(' C')作为LSB,表明您的架构是小端的。

在内存中编写一串字符(按顺序)并将其中的一些字符作为int读取,它会给出一个取决于字节序的数字。是的,在这种情况下,字节序很重要

答案 2 :(得分:1)

当谈论存储字节时,字节顺序并没有发挥作用,如s指向的char const数组。如果您在*s检查了内存,则会在小端解释为'a'时找到字节'b''c'int ...然而,它会被解释为"DCBA"

请记住,每个char已经是一个字节,如果你有char const * s = "0xfedcab09";并且你在一个小端系统上做了printf("%d", *(int const *)s);那么它会打印为0x9abcdef出现的十进制

答案 3 :(得分:0)

此处提出的混淆是由于符号

string “ABCDEF”可以多种方式解释(和存储)。

字符串 中,每个字母占用整个字节(char)。

char s[] = { 'A', 'B', 'C', 'D', 'E', 'F', 0 };

但是, 数字 ABCDEF的十六进制表示形式不同,每个数字(' 0' ...' 9'和' ...' F')仅代表四位或半字节。因此, number 0xABCDEF是字节序列

0xAB 0xCD 0xEF

这是 endianness 成为问题的地方:

  • Little Endian:最不重要的字节首先是int x = { 0xEF, 0xCD, 0xAB };
  • Big Endian:最重要的字节首先是int x = { 0xAB, 0xCD, 0xEF }
  • 混合Endian:<其他随机排序>
    int x = { 0xEF, 0x00, 0xCD, 0xAB }