【问题标题】:Why does printf pad an 8-bit char to 32-bits?为什么 printf 将 8 位字符填充为 32 位?
【发布时间】:2013-07-24 13:52:13
【问题描述】:
char byte = 0xff;
printf("%lu\n", sizeof(byte)) // Output is '1'
printf("%x\n", byte); // Output is 'ffffffff'

如果byte 的大小只有一个字节,那为什么printf() 表现得好像是四个字节?

【问题讨论】:

标签: c++ c types printf


【解决方案1】:

正式地,您的程序表现出未定义的行为:%x 格式规范需要unsigned int 类型的参数,但您传递的是int,如下所述(帽子提示@R)。这在现代二进制补码机器上实际上是无害的,因为 int 和 unsigned 具有兼容的位布局。但同样,从技术上讲,这是未定义的行为,最好修复它,如 printf("%x\n", (unsigned)byte);

将参数传递给可变参数函数的规则规定,所有小于 int 的整数类型都被提升为 int。否则,printf 怎么会在看到%x 时知道是从堆栈中抓取一个字节还是四个字节?来自标准:

5.2.2p7:
当给定参数没有参数时,参数的传递方式使得接收函数可以通过调用 va_arg(18.10)... 获取参数的值 如果参数具有整数或枚举类型,受整数提升(4.5),或受浮点提升的浮点类型(4.6),在调用前将参数的值转换为提升的类型。

这就是您的char 变成int 的方式。 char 是有符号还是无符号尚未明确,但显然,在您使用的平台上,它是有符号类型。因此,当提升为 int 时,它会进行符号扩展。 0xff(char)-10xffffffff(int)-1

【讨论】:

  • 你碰巧有这些规则的标准参考吗?
  • 5.2.2p7 当给定参数没有参数时,参数以这样一种方式传递,即接收函数可以通过调用 va_arg (18.10) 来获取参数的值... 如果参数具有整数或枚举类型,受整数提升 (4.5) 约束,或浮点类型受浮点提升 (4.6),参数的值在调用前转换为提升类型。
  • 这个答案不正确。问题是程序通过将错误的类型/值传递给 printf 来调用 UB。
  • 虽然这个 UB 是“无害的”,因为它不会格式化您的磁盘或让猴子飞出您的鼻子,但它仍然是有害的,因为它打印了错误的值。
【解决方案2】:

您通过将错误的参数类型传递给printf 来调用未定义行为。 %x 说明符需要 unsigned int 类型的参数,但您传递了(由于默认促销)签名的 int。如果带符号的int 参数的值为非负数,这可以说有效,但在您的系统上,纯char 恰好是带符号的类型,因此byte 包含以下结果将实现定义的转换应用到0xff;这种转换的通常结果是 -1。

【讨论】:

    【解决方案3】:

    我想是因为integer promotion

    关于这个概念的一篇很好的博文:http://www.idryman.org/blog/2012/11/21/integer-promotion/

    【讨论】:

      【解决方案4】:

      char 是 8 位有符号的。 "%x\n" 格式表示打印一个整数。所以byte 的值被符号扩展为一个整数。由于0xffchar 在这种情况下是-1 的8 位值,因此printf 只是打印-1 的十六进制整数值,即ffffffff

      【讨论】:

      • 在这个平台上,plain char 是一个有符号的 8 位数量。 C 标准明确指出,普通的 char 是有符号还是无符号是实现定义的细节。
      猜你喜欢
      • 2021-04-01
      • 2020-10-17
      • 2014-07-25
      • 2021-12-16
      • 2013-04-03
      • 2018-06-09
      • 2023-04-02
      • 2020-02-14
      • 2011-09-13
      相关资源
      最近更新 更多