为什么printf将8位字符填充到32位?

时间:2013-07-24 21:19:16

标签: c++ c types printf

char byte = 0xff;
printf("%lu\n", sizeof(byte)) // Output is '1'
printf("%x\n", byte); // Output is 'ffffffff'

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

4 个答案:

答案 0 :(得分:15)

正式地,您的程序表现出未定义的行为:%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

答案 1 :(得分:3)

我认为这是由integer promotion

引起的

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

char已签名为8位。 "%x\n"格式表示打印整数。因此byte的值被符号扩展为整数。由于char 0xff在此上下文中是8位值-1printf只是打印-1的十六进制整数值,ffffffff