base16中的printf char类型有混乱的现象

时间:2017-05-26 05:55:34

标签: c printf

以下是代码:

#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个字节。我知道charunsigned char之间的区别在于它们处理最高位的方式,但两者都保持一个字节。 而且我不认为该计划涉及任何转换过程。 如果c的类型为int(将unsigned char转换为int),则符号位将展开。但在这种情况下,unsigned char转换为char但是两个都有一个字节

那么为什么printf("%X",c)的结果包含4个字节?

2 个答案:

答案 0 :(得分:2)

如上所述,答案是整数提升,这确实有点难以理解:

1。它是什么:

整数提升表示小于int的整数类型会自动转换为int ,如果 int可以保存所有值原始整数类型(显然是charsigned charunsigned char的情况) - 否则它们会转换为unsigned int

2。什么时候发生:

整数提升基本上在两种情况下发生。

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 char0x80代表-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