我正在阅读此网站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个字节内吗?
答案 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 成为问题的地方:
int x = { 0xEF, 0xCD, 0xAB };
int x = { 0xAB, 0xCD, 0xEF }
int x = { 0xEF, 0x00, 0xCD, 0xAB }