问题描述
这是我书中的一个问题,
其实我也不知道对printf函数会有什么影响,所以就尝试了C lang原系统中的语句。这是我的代码:
#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);
}
解决方法
这道题有很多问题,不适合教授 C。
首先,要解决这个问题,我们必须假设使用了非标准的 C 实现。在标准 C 中,%x
是完整的转换规范,所以 %xu
和 %xd
不能;转换规范已在 u
或 d
之前结束。并且在转换规范中使用 z
会干扰其对 size_t
的标准使用。
尽管如此,我们假设这个 C 变体没有那些标准的转换规范,而是使用表中显示的那些,但这个 C 变体在其他方面符合 C 标准,但改动很小。
我们的下一个问题是,在 Y num = 42;
中,我们有一个普通的 Y
,而不是表中显示的 signed Y
或 unsigned Y
。让我们假设 signed Y
是有意的。
那么 num
是一个有符号的四位整数。它可以表示的最大值是 01112 = 710。所以它不能代表 42。尝试用 42 初始化它会导致 C 2018 6.3.1.3 指定的转换,部分说明:
否则,新类型是有符号的,值不能在其中表示;要么结果是实现定义的,要么引发实现定义的信号。
结果是我们不知道num
中的值是什么,甚至不知道程序是否继续执行;它可能会捕获并终止。
好吧,让我们假设这个实现只采用值的低位。 42 是 1010102,所以它的低四位是 1010。所以如果 num
中的位是 1010,那么它是负数。 C 标准允许使用多种表示负数的方法,但我们将假设最常见的一种,即二进制补码,因此 num
中的位 1010 表示 -6。
现在,我们进入 printf
语句。除了问题文本显示 Printf
,这不是由 C 标准定义的。 (你确定这个问题与 C 代码有关吗?)让我们假设它的意思是 printf
。
在printf("%xu",num);
中,如果转换规范应该像标准C中的那样工作,那么相应的参数应该是一个unsigned X
值,它已经被提升为int
用于函数调用。作为两位无符号整数,unsigned X
可以表示 0、1、2 或 3。未定义传递它 -6。所以我们不知道程序会打印什么。它可能只需要低两位,10,并打印“2”。或者它可能使用所有位并打印“-6”。这两者都符合以下要求:printf
的行为与为 在 unsigned X
可表示的范围内的值指定的一样。
在printf("%xd",num);
和printf("%yu",num);
中,存在同样的问题。
在 printf("%yd",num);
中,我们为 signed Y
转换规范正确传递了 signed Y
值,因此打印了“-6”。
然后 printf("%zu",num);
有同样的问题,类型的值不匹配。
最后,在 printf("%zd",num);
中,值再次处于正确的范围内,并打印“-6”。
从我们必须做出的所有假设以及未定义行为的所有点来看,您可以看到这是一次糟糕的练习。你应该质疑这本书的质量以及使用它的任何学校的质量。