C 大端和小端小混乱

C 大端和小端小混乱,c,pointers,endianness,C,Pointers,Endianness,我从这个网站上读到了关于小端和大端的表示 假设我们有一个数字0x01234567,那么在小尾端存储为(67)(45)(23)(01),在大尾端存储为(01)(23)(45)(67) 在上面的代码中看到这里的打印值后,字符串似乎存储为(BA)(DC)(FE) 为什么不像第一个示例中那样从LSB到MSB像(EF)(CD)(AB)一样存储?我认为endianess意味着在多字节中对字节进行排序。因此,排序应该与第二种情况中的“整2个字节”有关,而不是在这2个字节内,对吗?当谈到将字节存储在由s指向的c

我从这个网站上读到了关于小端和大端的表示

假设我们有一个数字0x01234567,那么在小尾端存储为(67)(45)(23)(01),在大尾端存储为(01)(23)(45)(67)


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


为什么不像第一个示例中那样从LSB到MSB像(EF)(CD)(AB)一样存储?我认为endianess意味着在多字节中对字节进行排序。因此,排序应该与第二种情况中的“整2个字节”有关,而不是在这2个字节内,对吗?

当谈到将字节存储在由
s
指向的char const数组中时,Endianness不起作用。如果您检查
*s
处的内存,您会发现字节
'a'
'b'
'c'
,当在小尾端系统上解释为
int
时,它会被解释为
“DCBA”


请记住,如果您有
char const*s=“0xfedcab09”,则每个
char
已经是一个字节printf(“%d”,*(int const*)s)
在一个小的endian系统上,然后它将以十进制形式输出0x9abcdef。

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

memAddr  |  0  |  1  |  2  |  3  |  4  |  5  |  6   |
data     | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | '\0' |
            ^ s points here
                        ^ p+1 points here
memAddr  |  0   |  1   |  2   |  3   |  4   |  5   |  6   |
data     | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x00 |
            ^ s points here
                          ^ p+1 points here
现在,看起来您使用的是ASCII编码,所以这就是内存中真正的内容

memAddr  |  0  |  1  |  2  |  3  |  4  |  5  |  6   |
data     | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | '\0' |
            ^ s points here
                        ^ p+1 points here
memAddr  |  0   |  1   |  2   |  3   |  4   |  5   |  6   |
data     | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x00 |
            ^ s points here
                          ^ p+1 points here
所以对于一个小的endian机器,这意味着对于一个多字节类型,最低有效字节排在第一位。对于单个字节
char
,没有endianess的概念。ASCII字符串只是一个字符字符串。。这是永无止境的。您的
int
s是2个字节。因此,对于从内存位置2开始的
int
,该字节的有效性最低,地址3处的字节的有效性最高。这意味着这里的数字,即人们通常读取数字的方式,是0x4443(以10为基数的17475,“DC”为ASCII字符串),因为内存位置3中的0x44比内存位置2中的0x43更重要。当然,对于big-endian,这是相反的,数字是0x4344(以10为底的17220,“CD”是ASCII字符串)

编辑:

针对您的评论。。。
c
字符串是以
NUL
结尾的
char
s数组,这是绝对正确的。Endianess仅适用于基元类型,
short、int、long、long
等(“基元类型”可能是不正确的命名法,知道的人可以纠正我)。数组只是连续内存的一部分,其中1个或多个类型直接相邻,按顺序存储。对于整个数组没有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;
这就是内存的样子:不管是大的还是小的endian机器,它都是这样

memAddr   |    0-1   |    2-3   |    4-5   |
data      | array[0] | array[1] | array[2] |
请注意,数组元素没有endianess的概念。无论元素是什么,这都是正确的。元素可以是基元类型、
structs
、任何类型。数组中的第一个元素始终位于
数组[0]

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

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]
最低有效字节位于第一位。big-endian机器的外观如下所示:

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]
请注意,数组中每个元素的内容都会受到endianess的影响(因为它是一个基元类型的数组。。如果它是一个
结构的数组
,则
结构
成员不会受到某种endianess反转的影响,endianess只适用于基元)。然而,无论是在大端元还是小端元机器上,数组元素的顺序都是相同的

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

char word[] = "hey";
这就是你的记忆:

memAddr   |    0    |    1    |    2    |    3    |
data      | word[0] | word[1] | word[2] | word[3] |
                  equals NUL terminator '\0' ^
memAddr   |  0   |  1   |  2   |  3   |
data      | 0x68 | 0x65 | 0x79 | 0x00 |
就在这种情况下,
word
数组的每个元素都是一个字节,并且只有一种方法可以对单个项目进行排序,因此无论是在小型或大型endian机器上,这都是内存中的内容:

memAddr   |    0    |    1    |    2    |    3    |
data      | word[0] | word[1] | word[2] | word[3] |
                  equals NUL terminator '\0' ^
memAddr   |  0   |  1   |  2   |  3   |
data      | 0x68 | 0x65 | 0x79 | 0x00 |

Endianess仅适用于多字节基元类型。我强烈建议在调试器中四处搜索,以便在实际操作中看到这一点。所有流行的IDE都有内存视图窗口,或者您可以使用
gdb
。在
gdb
中,您可以将内存打印为字节、半字(2字节)、字(4字节)、巨字(8字节)等。在小型endian机器上,如果您将字符串打印为字节,您将按顺序看到字母。以半字打印,您将看到每2个字母“反转”,每4个字母“反转”,等等。在big-endian机器上,它将以相同的“可读”顺序打印。

这里出现的混淆是由于符号造成的

字符串“ABCDEF”可以以多种方式解释(和存储)

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

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

0xAB 0xCD 0xEF
这就是endianness成为问题的地方:

  • 小尾端:最低有效字节第一
    intx={0xEF,0xCD,0xAB}
  • Big-Endian:最高有效字节优先
    intx={0xAB,0xCD,0xEF}
  • 混合尾端:
    intx={0xEF,0x00,0xCD,0xAB}

    • 字符串之间似乎有点混淆

      1)  "ABCDEF"
      
      号码是11259375 w