【问题标题】:endianness when using part of int array使用部分 int 数组时的字节顺序
【发布时间】:2011-10-24 18:53:39
【问题描述】:

我正在尝试从 uint8_t 数组中提取值。 但是我很难理解这些在内存中是如何表示的。

#include <cstdio>
#include <cstring>
#include <stdint.h>
int main(){
  uint8_t tmp1[2];
  uint16_t tmp2 = 511;//0x01 + 0xFF = 0x01FF
  tmp1[0] = 255;//0xFF
  tmp1[1] = 1;//0x01
  fprintf(stderr,"memcmp = %d\n",memcmp(tmp1,&tmp2,2));


  fprintf(stderr,"first elem in uint8 array  = %u\n",(uint8_t) *(tmp1+0));
  fprintf(stderr,"first elem in uint8 array  = %u\n",(uint8_t) *(tmp1+1));

  fprintf(stderr,"2xuint8_t as uint16_t  = %u\n",(uint16_t) *tmp1);
  return 0;
}

所以我有一个数据类型为 uint8_t 的 2 元素长数组。我有一个变量 uint16_t。 所以当我在我的小端机器上取值 511 时,我会假设它在内存中布局为

0000 0001 1111 1111

但是当我使用 memcompare 时,看起来它实际上被表示为

1111 1111 0000 0001 

那么小字节序只在每个字节“内”使用? 而且由于在 tmp1[1] 中设置的单个位计为 256,即使它在我的流中更“正确”。因此,每个字节(不是位)的值是 bigendian 吗?我对此有点困惑。

另外,如果我想强制 fprint 打印输出,我的 2xuint8_t 作为单个 uint16_t,我该怎么做。下面的代码不起作用,它只打印第一个字节。

fprintf(stderr,"2x uint8_t as uint16_t  = %u\n",(uint16_t) *tmp1);

提前致谢

【问题讨论】:

  • CPU 知道如何做小端,你不知道。
  • @Patrick 只要你不与其他机器通信,它们有另一个字节序或者只是做聪明的字节技巧。虽然在大多数情况下您实际上不必为此烦恼,但理解并牢记这一点很重要。

标签: c++ c arrays integer bit-manipulation


【解决方案1】:

你对你期望的假设是倒退的。您的观察结果与 little-endian 表示一致。要回答你的最后一个问题,它看起来像这样:

fprintf(stderr,"2x uint8_t as uint16_t  = %u\n",*(uint16_t*)tmp1);

【讨论】:

    【解决方案2】:

    不要将字节顺序视为“字节内”。将其视为“字节排序”。 (也就是说,实际的位顺序无关紧要,因为人类通常以大端方式读取值。)如果想象在小端机器上位是颠倒的,你可以这样想象。 (在这种情况下,你的例子看起来像1111 1111 1000 0000,但正如我所说,人类通常不会读取最重要的值在右边的数字......但你可能想想象这就是计算机的方式看东西,如果它可以帮助你理解小端。)

    在小端机器上,0xAABBCCDD 在内存中将被视为0xDD 0xCC 0xBB 0xAA,正如您所看到的。在大端机器(例如 PPC 盒)上,您会在内存中看到与写出 32 位字时相同的顺序。

    【讨论】:

      【解决方案3】:

      首先,如果你想 100% 确定你的变量在内存中以正确的顺序存储,你应该把它们放在一个结构中。

      然后请注意,memcmp() 将您提供的输入视为字节序列,因为它对您提供的数据的性质没有任何假设。例如,考虑以下代码:

      #include <stdio.h>
      #include <stdint.h>
      
      int main(int argc, char** argv) {
          int32_t a, b;
          a = 1;
          b = -1;
          printf( "%i\n", memcmp( &a, &b, sizeof( int32_t ) ) );
      }
      

      它在我的 little-endian 机器上输出 -254,而不管 a > b。这是因为它不知道内存到底是什么,所以它像一个 uint8_t 数组一样比较它们。

      如果你真的想可视化数据在你的机器上是如何表示的,你可以先使用 fwrite 将一个结构写入文件,然后用你最喜欢的十六进制编辑器打开它(根据我的经验,wxHexEditor 可以很好地告诉你如果数据是 X-bit Y-endian ingeter,数据看起来如何)。这是来源:

      #include <stdio.h>
      #include <stdint.h>
      
      typedef struct {
          uint8_t tmp1[2];
          uint16_t tmp2;
      } mytmp;
      
      int main(int argc, char** argv) {
          mytmp tmp;
          tmp.tmp1[0] = 255;
          tmp.tmp1[1] = 1;
          tmp.tmp2 = 511;
      
          FILE* file = fopen( "struct-dump", "w" );
          fwrite( &tmp, sizeof( mytmp ), 1, file );
          fclose( file );
      }
      

      至于将 uint8_t 数组视为 uint16_t,您可能需要声明 union 或使用指针强制。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-26
        • 2023-03-18
        • 1970-01-01
        相关资源
        最近更新 更多