【问题标题】:Does printf() print with endianness?printf() 是否以字节顺序打印?
【发布时间】:2021-10-19 07:13:06
【问题描述】:

我有一个小sn-p:

int main()
{
        unsigned long long x = 0x0000000000008342;
        unsigned long long * x_p = &x;
        unsigned int * y_p = (unsigned int *)x_p;
        unsigned int y = *y_p;
        printf("y = %#.8x\n", y);
}

使用 little endian,这就是数字的存储方式。

0x00: 42 83 00 00
0x04: 00 00 00 00

但是为什么打印的是 0x00008342 而不是 0x00004283 呢?

【问题讨论】:

  • 唯一存储在内存中的值是 a 初始化的值。编译器不会存储像0x7788aabb 这样的整数文字。并且当您在初始化中截断位数时,只会存储0x0000aabb
  • 还要注意这里不涉及字节序,无论字节序如何,转换都会截断为最低 16 位。而这 16 个最低位将永远是0xaabb
  • a 的值在 16 位 int 的机器上可能不同
  • 您在 C 中用于整数的表示法不依赖于您使用的硬件上的字节序类型。在 C 中将 long 截断为 short 也不取决于硬件上的字节序类型。如果您获取一个整数的地址,并访问它所包含的字节,那么这很重要。
  • 我不确定是什么让您感到困惑。您似乎很清楚,在小端机器上写入期间,最低有效字节到达最低地址。美好的。那么,为什么您会惊讶于在读取过程中从最低地址读取最低有效字节。我的意思是这是一个对称操作。

标签: c linux


【解决方案1】:

字节序适用于所有大于一个字节的整数类型。我不明白为什么您认为字节序仅适用于您的 64 位整数类型而不适用于 int... 这似乎是您困惑的根源。

您的代码的一个主要问题是unsigned int y = *y_p; 是未定义的行为。 What is the strict aliasing rule? 所以不能假定您的程序具有确定性行为。

如果要实际打印存储在内存中的字节,则需要逐字节进行:

for(size_t i=0; i<sizeof x; i++)
  printf("%.2X ", ((unsigned char*)&x)[i] );

这种转换很好,因为字符类型是严格别名的特殊例外。它按预期打印42 83 00 00 00 00 00 00

此外,您在此处还有一个小问题:0x0000000000008342。不要像认为你已经写了一个 64 位整数常量那样写前导零。这个类型其实是int(32位系统)或者unsigned int(8/16位系统)。前导零不起作用,您需要附加 ull 后缀。这在这个特定的 sn-p 中不是问题,但如果您将这种风格带入实际程序中,可能会成为问题。

【讨论】:

    【解决方案2】:

    printf("%x\n", unsigned_number); 将以十六进制打印unsigned_number,就像printf("%u\n", unsigned_number); 将以十进制打印一样。

    两者都不关心unsigned_number 的内部表示。 printf("%x",...) 不执行 hexdump(当然,除非您在数据的每个字符上循环调用它)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-29
      • 2020-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-17
      相关资源
      最近更新 更多