c - 使用格式说明符进行转换
问题描述
当我们使用格式说明符打印数据时,我无法推断机器内部发生的事情。
我试图理解有符号和无符号整数的概念,结果如下:
unsigned int b=-12;
printf("%d\n",b); //prints -12
printf("%u\n\n",b); //prints 4294967284
我猜b实际上将-12的二进制版本存储为11111111111111111111111111110100。
因此,由于 b 是无符号的,b 技术上存储 4294967284。但格式说明符 %d 仍然导致 b 的二进制值被打印为其有符号版本,即 -12。
然而,
printf("%f\n",2); //prints 0.000000
printf("%f\n",100); //prints 0.000000
printf("%d\n",3.2); //prints 2147483639
printf("%d\n",3.1); //prints 2147483637
我有点希望根据类型转换规范将 2 打印为 2.00000 和 3.2 打印为 3。
为什么这不会发生?在机器级别究竟发生了什么?
解决方案
格式说明符和参数类型不匹配(如使用浮点说明符"%f"
打印int
值)会导致未定义的行为。
请记住,这2
是一个整数值,可变参数函数(如printf
)并不真正知道参数的类型。该printf
函数必须依赖格式说明符来假设参数是指定的类型。
为了更好地理解你如何得到你得到的结果,为了理解“内部发生的事情”,我们首先必须做出两个假设:
- 系统使用 32 位作为
int
类型 - 系统使用 64 位作为
double
类型
现在会发生什么
printf("%f\n",2); //prints 0.000000
是该printf
函数看到说明"%f"
符,并将下一个参数作为 64 位double
值获取。由于int
您在参数列表中提供的值只有 32 位,因此该double
值中的一半位将是未知的。然后该printf
函数将打印(无效)double
值。如果你不走运,一些未知位可能会导致该值成为可能导致崩溃的陷阱值。
同样与
printf("%d\n",3.2); //prints 2147483639
该printf
函数获取下一个参数作为 32 位值,丢失作为实际参数提供int
的 64 位值中的一半位。double
将哪些 32 位复制到内部int
值中取决于字节顺序。整数没有陷阱值,因此不会发生崩溃,只会打印一个意外的值。
推荐阅读
- symfony - Symfony4 - 在两个实体管理器之间共享缓存池,这是一个坏主意还是我遇到了错误?
- excel - 检索具有相同级别名称的多个 XML 节点
- javascript - 将 Styled 组件作为 className 传递给另一个组件
- asp.net - 如何控制 NSwag 文档中包含的模型
- silverstripe - CMS 路由(设置)的 SilverStripe 功能测试始终为 POST 请求返回 404
- xamarin.android - listview 项目空间 xamarin android
- php - 如何在一次 MySQL 数据库更新中做多个数学方程?
- multithreading - 尝试使用 vTaskList() 列出所有任务时出现硬故障
- visual-studio - 如何正确导入 Xamarin 项目?
- java - 使用 JMS ObjectMessage 时发生 ClassNotFound 异常