char byte = 0xff;
printf("%lu\n", sizeof(byte)) // Output is '1'
printf("%x\n", byte); // Output is 'ffffffff'
如果byte
的大小只有一个字节,那么printf()
为什么表现得好像是四个字节?
答案 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)-1
,0xffffffff
为(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位值-1
,printf
只是打印-1
的十六进制整数值,ffffffff
。