以下是代码:
#include<stdio.h>
void f(unsigned char v)
{
char c = v;
unsigned char uc = v;
printf("%%X: %X, %X\n", c, uc);
}
int main(int argc, char *argv[])
{
f(0x80);
return 0;
}
结果:
%X: FFFFFF80, 80
我很困惑。 FFFFFF80
如何来。我们知道char
类型包含1个字节。我知道char
和unsigned char
之间的区别在于它们处理最高位的方式,但两者都保持一个字节。
而且我不认为该计划涉及任何转换过程。
如果c
的类型为int
(将unsigned char转换为int),则符号位将展开。但在这种情况下,unsigned char
转换为char
,但是两个都有一个字节。
那么为什么printf("%X",c)
的结果包含4个字节?
答案 0 :(得分:2)
如上所述,答案是整数提升,这确实有点难以理解:
整数提升表示小于int
的整数类型会自动转换为int
,如果 int
可以保存所有值原始整数类型(显然是char
,signed char
和unsigned char
的情况) - 否则它们会转换为unsigned int
。
整数提升基本上在两种情况下发生。
1)在算术表达式中:
signed char x = 40;
signed char y = 100;
unsigned char z = x + y; // <-- here, the addition is done with two ints
2)在函数参数中,如果参数是一个可变参数(比如调用printf
时)或者函数没有原型,IOW,如果参数类型不知道强>
char x = 'A';
printf("value: %d\n", x); // <-- here, x is passed as an int
因此,您问题的答案是:对于signed char
,0x80
代表-128
。 -128
int
表示为0xffffff80
。
答案 1 :(得分:2)
printf
是一个可变函数,定义为:
int printf(const char * fmt, ...);
也就是说,printf
不知道你传递给它的参数类型,它依赖于格式字符串来推导出参数类型。
格式字符串后面的每个参数都受整数提升(char
提升为int
)。
因此,printf
在您的案例中收到的是格式字符串("%%X: %X, %X\n"
),int
包含-128
(因为0x80
表示为{{ 1}}在二进制补码架构上char
)和-128
包含int
。
参考文献:
ISOC§6.3.1.1:
如果
128
可以表示原始类型的所有值,则为该值 转换为int
;否则,它被转换为int
。这些称为 整数促销 。
ISOC§6.5.2.2:
如果表示被调用函数的表达式有一个 不包含原型的类型, 整数 对每个参数和参数执行促销 将类型
unsigned int
提升为float
。这些被称为 默认参数促销 。函数原型声明符中的省略号表示法 导致参数类型转换在最后声明后停止 参数。执行 默认参数促销 尾随论据。
P.S。
值得注意的是,您遇到的两个补码行为是实现定义的,即double
不能保证在所有平台上都等于(char)0x80
。