首页 > 解决方案 > 使用格式说明符进行转换

问题描述

当我们使用格式说明符打印数据时,我无法推断机器内部发生的事情。

我试图理解有符号和无符号整数的概念,结果如下:

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。

为什么这不会发生?在机器级别究竟发生了什么?

标签: ctype-conversion

解决方案


格式说明符和参数类型不匹配(如使用浮点说明符"%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值中取决于字节顺序。整数没有陷阱值,因此不会发生崩溃,只会打印一个意外的值。


推荐阅读