首页 > 解决方案 > 类型转换对 printf 函数的影响

问题描述

这是我书中的一个问题,

在此处输入图像描述

其实我也不知道对printf函数有什么影响,所以我尝试了C语言原系统中的语句。这是我的代码:

#include <stdio.h>

void main() {
  int x = 4;
  printf("%hi\n", x);
  printf("%hu\n", x);
  printf("%i\n", x);
  printf("%u\n", x);
  printf("%li\n", x);
  printf("%lu\n", x);
}

在线尝试!

因此,输出非常简单。但是,这真的是解决上述问题的方法吗?

标签: cformattingprintfbehavior

解决方案


这个问题存在许多问题,使其不适合教授 C。

首先,要解决这个问题,我们必须假设使用了非标准的 C 实现。在标准 C 中,%x是一个完整的转换规范,所以%xu%xd不可能;u转换规范在or之前已经结束d。并且z在转换规范中的使用会干扰其对 . 的标准使用size_t

尽管如此,让我们假设这个 C 变体没有那些标准转换规范,而是使用表中显示的那些,但是这个 C 变体在其他方面符合 C 标准,而且改动很小。

我们的下一个问题是,在 中Y num = 42;,我们有一个普通的Y,而不是表中显示的signed Yor unsigned Y。让我们假设signed Y是有意的。

然后num是一个有符号的四位整数。它可以表示的最大值是 0111 2 = 7 10。所以它不能代表 42。尝试用 42 初始化它会导致 C 2018 6.3.1.3 指定的转换,其中部分表示:

否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号。

结果就是我们不知道里面有什么值,num甚至不知道程序是否继续执行;它可能会陷入困境并终止。

好吧,让我们假设这个实现只取值的低位。42是1010102,所以它的低四位是1010。所以如果里面的位num是1010,就是负数。C 标准允许负数的几种表示方法,但我们将假设绝大多数最常见的方法,即二进制补码,因此位 1010num表示 -6。

现在,我们开始printf陈述。除了问题文本显示之外Printf,C 标准没有定义它。(你确定这个问题与 C 代码有关吗?)让我们假设它的意思是printf.

printf("%xu",num);中,如果转换规范应该像标准 C 中的那样工作,那么相应的参数应该是一个unsigned X已被提升为int函数调用的值。作为一个两位无符号整数,anunsigned X可以表示 0、1、2 或 3。传递它 -6 没有定义。所以我们不知道程序会打印什么。它可能只需要低两位,10,并打印“2”。或者它可能会使用所有位并打印“-6”。这两者都符合对于在 可表示的范围内的值的行为printf指定的要求。unsigned X

printf("%xd",num);printf("%yu",num);中,存在同样的问题。

printf("%yd",num);中,我们正确地传递了转换规范的signed Ysigned Y,因此打印了“-6”。

然后printf("%zu",num);与类型不匹配的值有相同的问题。

最后,在 中printf("%zd",num);,值再次在正确的范围内,并打印“-6”。

从我们必须做出的所有假设以及行为未定义的所有点中,您可以看到这是一个糟糕的练习。你应该质疑它所在的书和任何使用它的学校的质量。


推荐阅读