c - GCC fprintf:应该是 int(32 位)还是 char(8 位)?
问题描述
哪些代码是有效的?我在输出上得到零个字符,想知道这是否是由于将字符处理不当造成的,反之亦然。%c 说明符是应该打印的,我只是不确定最后一个参数。
int c;
fprintf(stdout, "%c", c);
int n;
fprintf(stdout, "%c", n);
关于scanf的同样问题,应该是char还是int还是其中之一?
解决方案
两者都很好。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 /6
and/7
和6.3 Conversions
)
...整数提升在每个参数上执行,并且具有浮点类型的参数被提升为双精度。这些称为默认参数提升。
函数原型声明器中的省略号会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是在尾随参数上执行的。
如果 an
int
可以表示原始类型的所有值(受宽度限制,对于位域),则该值转换为 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
推荐阅读
- python - 我该如何解决这个下载铬问题
- api - 当我尝试通过 keycloak 调用我的安全 API 时收到状态 401 Unauthorized
- r - 闪亮的反应自称
- mysql - Springboot版本升级——我的sql报错
- keras - 如何在预测中我不知道的神经网络值中传递输入
- substrate - 基板前端模板连接本地主机错误
- swift - 返回基于约束的类型,SwiftUI
- python - 如何在使用 python 时添加一行
- http - 如何以 zip 格式提供文件?
- azure-devops - Azure DevOps yaml 管道:配置 Azure Artifacts“包”资源