间接操作符是否会更改内存表示?

时间:2015-08-28 23:29:53

标签: c++ memory uint8t

好的,我觉得这很愚蠢,但为什么下面的代码会输出不同的行?

要打印第一行,我将地址写入数组的第一个字节,将其解释为指向uint16_t的指针,取值并逐个打印它的位。

对于第二行,我取一个指向第一个字节的指针,将其解释为指向uint8_t的指针,取值并逐个打印它的位。然后对第二个字节执行相同的操作。

由于我没有修改为数组分配的内存,只能以不同的方式解释它,我希望输出相同,但字节顺序不同。

我可能会错过一些东西,但我唯一的猜测就是间接算子会做一些我不期望的事情。

#include <iostream>
#include <string.h>


 int main() {
   uint8_t u[2];
   u[0] = 170;
   u[1] = 85;

  for(int i = 15; i >= 0; --i) {
    printf( "%u", (((*((uint16_t*)u)) >> i) & 0x0001));
  }
  printf( "\n");
  for(int i = 7; i >= 0; --i) {
    printf( "%u", (((*((uint8_t*)u)) >> i) & 0x01));
  }
  for(int i = 7; i >= 0; --i) {
    printf( "%u", (((*((uint8_t*)(u + 1))) >> i) & 0x01));
  }
}

Outout

0101010110101010 
1010101001010101

更新#1:请忽略分配,是的示例代码不适用于每个操作系统,但它只是一个简化的示例。

更新#2:我知道字节序,但我错过的是逻辑与物理位表示。在上面的示例中,即使物理表示未更改,我也会打印受字节序影响的逻辑表示。非常感谢@ john-kugelman解释这一点。

3 个答案:

答案 0 :(得分:6)

在基于Intel的平台上,号码存储在little endian order中。最低有效字节是第一个,最重要的是最后一个。这与我们传统阅读数字的方式相反。如果我们用小端而不是大端命令编写数字,那么将会写一千二百三十1023而不是{{1}}。

当您将字节数组中的字节解释为16位整数时,第一个字节(170)被解释为最低有效字节,第二个字节(85)被解释为最高有效字节。但是当你自己打印字节时,你会以相反的顺序打印它们。这就是不匹配的来源。

Endianness是特定于平台的属性。大多数非英特尔架构使用更多&#34;自然&#34;大端序。对我们来说不幸的是,基于英特尔的架构是最常见的。碰巧的是,几乎所有网络流量都是大端,也称为网络字节顺序&#34;。当基于英特尔的机器在互联网上通话时,他们会在发送和接收数据时进行大量的字节交换。

  

如果我打印uint16_t本身,我预计会发生这种不匹配。我不明白的是,为什么当我试图得到它的时候会发生这种情况。

通过位屏蔽和移位操作读取其位并不从左到右读取存储器中的物理位,它从中读取逻辑位最重要的。在小端架构上,最重要到最不重要的等同于从右到左的顺序。

另请注意,字节序表示交换字节,而不是。在小端架构中,比特不是交换的,字节是。比特无法互换,因为它们无法单独寻址。你只能用轮班和面具来接待他们。

答案 1 :(得分:1)

可能的aligment错误和遗漏的格式字符串长度修饰符不在考虑范围内,您会遇到字节序问题。该术语描述了如何将数据类型长于最小可寻址单元(即一个字节)存储在存储器中。

您的系统似乎对16位整数使用小端:低位字节存储在较低的地址。

注意没有理由为后两个for循环进行强制转换,因为您使用的是与array-elements相同的类型。永远不要在没有充分理由的情况下进行投射,并且总是尝试编写你不必投射的代码转换可防止编译器帮助您检测类型不匹配。所以如果你绝对确定你比编译器更了解你正在做什么,那么你只能进行投射。

答案 2 :(得分:1)

内存中的两个字节:

和0xAA

0x55的

当它们被解释为16位字时,有两个可能的值。

基于处理器的字节顺序:

Little Endian(最低有效字节优先):0x55AA // Intel x86 / x64

Big Endian(最重要的字节优先):0xAA55 // Power,ARM等