首页 > 解决方案 > GCC fprintf:应该是 int(32 位)还是 char(8 位)?

问题描述

哪些代码是有效的?我在输出上得到零个字符,想知道这是否是由于将字符处理不当造成的,反之亦然。%c 说明符是应该打印的,我只是不确定最后一个参数。

int c;
fprintf(stdout, "%c", c);
int n;
fprintf(stdout, "%c", n);

关于scanf的同样问题,应该是char还是int还是其中之一?

标签: cgccprintfscanf

解决方案


两者都很好。ISO C11 标准在7.21.6.1 The fprintf function /9(所有各种*printf*scanf调用都用fprintf和定义fscanf)中声明:

如果任何参数不是相应转换规范的正确类型,则行为未定义。

但是,在%c( /8) 部分中,它还指出(我的重点):

如果不存在l长度修饰符,则将int参数转换为unsigned char,并写入结果字符。

事实上,传递 anint或 achar没有区别,因为默认参数提升是在省略号之外的 varargs 类型函数上执行的(根据6.5.2.2 Function calls /6and/76.3 Conversions

...整数提升在每个参数上执行,并且具有浮点类型的参数被提升为双精度。这些称为默认参数提升。

函数原型声明器中的省略号会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是在尾随参数上执行的。

如果 anint可以表示原始类型的所有值(受宽度限制,对于位域),则该值转换为 int;否则,它将转换为无符号整数。这些被称为整数促销。

所以,因为fprintf是这样定义的:

int fprintf(FILE * restrict stream, const char * restrict format, ...);

这意味着char参数将升级为int无论如何。


fscanf另一回事。7.21.6.2 The fscanf function /12它在(再次强调)中指出:

如果不存在l长度修饰符,则相应的参数应是指向字符数组的初始元素的指针,该字符数组的大小足以接受序列。不添加空字符。

这意味着您应该提供字符(或字符数组)的地址。如果您提供的int大小不同,您可能只会看到其中的一部分发生了int变化,其余部分将保留为任意值。例如,在八位字节、四字节int、大端系统上:

+------+------+------+------+
| 0x12 | 0x34 | 0x56 | 0x78 | <- Initial value of int 0x12345678
+------+------+------+------+
| 0x36 | .... | .... | .... | <- Read character '6' (0x36 in ASCII)
+------+------+------+------+
| 0x36 | 0x34 | 0x56 | 0x78 | <- Final value of int 0x36345678
+------+------+------+------+

您可以看到其他字节保持int不变(由 表示....),导致最终值int不是.0x36


推荐阅读