为什么在printf中指定为整数的char被正确打印

Nig*_*n23 3 c printf types stdio type-conversion

为什么以下代码有效?

char c = 'A';
printf("%d - size: %d", c, sizeof(c));
Run Code Online (Sandbox Code Playgroud)

打印出来:

65 - size: 1
Run Code Online (Sandbox Code Playgroud)

为什么输出不是垃圾,因为int通常是4个字节长,我们可以清楚地看到char是1个字节长.编译器是否进行隐式对话?

dbu*_*ush 5

排名低于的任何整数类型int都将提升为表达式中使用的任何一个intunsigned int任何时候.这在C标准的6.3.1.1p2节中规定:

如果可以使用int或unsigned int,则可以在表达式中使用以下内容:

  • 具有整数类型(int或unsigned int除外)的对象或表达式,其整数转换等级小于或等于int和unsigned int的等级.
  • _Bool,int,signed int或unsigned int类型的位字段.

如果int可以表示原始类型的所有值(由宽度限制,对于位字段),则该值将转换为int; 否则,它将转换为unsigned int.这些被称为整数促销.

整数促销不会更改所有其他类型

这就是在这种情况下发生的事情,因为printf函数在编译时不会隐式地知道其参数的类型.所以char参数被提升为int,并且使用%d格式化它是有效的.


Ste*_*mit 5

对于具有可变长度参数列表的函数,有一个特殊规则,例如printf.在参数列表的可变长度部分中,所有小于的参数int都被提升为int,并float被提升为double.所以事实证明使用打印字符(或a short)是完全正常的%d.

这些默认参数促销最终会导致一些异常现象printf.你可能会认为,正确的格式说明char,short,int,float,和double%hhd,%hd,%d,%f,和%lf分别.但事实上,你可以逃脱%d,%d,%d,%f,和%f. printf基本上忽略了l浮点的修饰符,它似乎忽略了h整数的修饰符.(h正如chux在评论中解释的那样,实际上可以在不起眼的情况下产生影响.)