5

我正在研究 K&R 第二版,但无法弄清楚为什么我会得到某个结果。我要解决的问题是计算数据类型的上限和下限。具体来说:

“编写一个程序来确定 char 、 short 、 int 和 long 变量的范围,包括有符号和无符号,方法是从标准头文件中打印适当的值并通过直接计算。如果你计算它们更难:确定各种浮点数的范围-点类型。”

我已经了解了按位运算符和二进制的恭维,并且有一个我认为应该适用于有符号数据类型的解决方案,但它适用于无符号数据类型,这对我来说没有任何意义。这是代码:

#include <stdio.h>

main()
{
    signed int i;

    i = ~0;
    i >>= 1;
    printf("Upper limit: %d\n", i);
    printf("Lower limit: %d\n", -i -1);
}

这将导致为上限打印 -1,为下限打印 0。但是,如果我将 i 更改为无符号整数,我会得到我期望的结果(2147483647 和 -2147483648)。我无法解决这个问题,因为我的理解是 unsigned int 永远不能小于 0,并且有符号 int 应该使用这些按位运算符工作,即,如果它是 32 位系统,

~0 == 11111111111111111111111111111111

, 和

~0 >> 1 == 011111111111111111111111111111111, 
           or 2147483647.

知道我哪里出错了吗?

4

5 回答 5

6

通过使用%d您将您的价值视为signed继续进行printf

你可以%u改用。

添加

正如 Magn3s1um指出的那样,您无需指定signed,并且unsigned您的特定任务printf将为您完成所有工作。

于 2013-07-22T19:46:38.573 回答
4

输出:

  1. 注意:
    “在表达式i >>= 1中,负值右移。C 标准说这是一个实现定义的操作,许多实现将它定义为算术移位。在算术移位中,最高有效位保持不变(保持 MSB(有符号位)= 1)”。

    (您可以阅读: C中的右移负数>>取决于编译器是单移还是非正移,但可能在您的情况下它进行算术移位。)

    出于这个原因,在代码之后:

     i = ~0;  
     i >>= 1;
    

    i仍然~0。那是二进制 == 11111111111111111111111111111111

    并且因为~0==11111111111111111111111111111111是 == 2'c 的补1-1

    因此,当您使用格式字符串打印时,%d它会打印-1。您应该使用%u打印最大无符号值 == ~0

    此处需要注意的重要事项:

    §6.2.6.2 语言 45,©ISO/IEC ISO/IEC 9899:201x

    (一个人的补码)。哪一个适用 implementation-defined,符号位1 和所有值位为零(对于前两个)或符号位和所有值位为 1(对于一个补码)的值是陷阱表示还是正常值. 在符号和幅度以及一个的补码的情况下,如果这个表示是一个正常值,它被称为负零。

    您的理解:

    ~0 >> 1 == 011111111111111111111111111111111是错的!(根据输出,它可能在您的系统中发生但不会发生)

    ~0 >> 1 == 111111111111111111111111111111111,注意 MSB(有符号位)是1

    对于无符号班次,请尝试以下操作:

    ~0U >> 1 == 011111111111111111111111111111111

    注意未签名的后缀U

  2. 第二个 printf
    因为iis -1,所以在第二个表达式中-i - 1== - (-1) - 1== 1 - 1==0所以输出为零:0

于 2013-07-22T19:46:53.590 回答
3

您的编译器将 >> 实现为算术移位。因此,MSB 将其值保持为 1,并且移位不执行任何操作。

也就是说, ~0 >> 1 仍然是 ~0 因为移位符号扩展。

见这里:https ://stackoverflow.com/a/7632/1974021

于 2013-07-22T19:48:02.000 回答
3

您可能对limits.hfloat.h头文件中的常量感兴趣

来自limits.h

+------------+------------------------------------------------------------------+--------------------------------+
| CHAR_BIT   | Number of bits in a char object (byte)                           | 8 or greater                   |
| SCHAR_MIN  | Minimum value for an object of type signed char                  | -127 (-2^7+1) or less          |
| SCHAR_MAX  | Maximum value for an object of type signed char                  | 127 (2^7-1) or greater         |
| UCHAR_MAX  | Maximum value for an object of type unsigned char                | 255 (2^8-1) or greater         |
| CHAR_MIN   | Minimum value for an object of type char                         | either SCHAR_MIN or 0          |
| CHAR_MAX   | Maximum value for an object of type char                         | either SCHAR_MAX or UCHAR_MAX  |
| MB_LEN_MAX | Maximum number of bytes in a multibyte character, for any locale | 1 or greater                   |
| SHRT_MIN   | Minimum value for an object of type short int                    | -32767 (-2^15+1) or less       |
| SHRT_MAX   | Maximum value for an object of type short int                    | 32767 (2^15-1) or greater      |
| USHRT_MAX  | Maximum value for an object of type unsigned short int           | 65535 (2^16-1) or greater      |
| INT_MIN    | Minimum value for an object of type int                          | -32767 (-2^15+1) or less       |
| INT_MAX    | Maximum value for an object of type int                          | 32767 (2^15-1) or greater      |
| UINT_MAX   | Maximum value for an object of type unsigned int                 | 65535 (2^16-1) or greater      |
| LONG_MIN   | Minimum value for an object of type long int                     | -2147483647 (-2^31+1) or less  |
| LONG_MAX   | Maximum value for an object of type long int                     | 2147483647 (2^31-1) or greater |
| ULONG_MAX  | Maximum value for an object of type unsigned long int            | 4294967295 (2^32-1) or greater |
+------------+------------------------------------------------------------------+--------------------------------+
于 2013-07-22T19:51:33.020 回答
1

当您对 执行位移时i,编译器将其视为i有符号量,并执行算术右移。您似乎希望该行代码执行逻辑右移。

换行

i >>= 1;

i = ((unsigned int)i) >> 1;

然后它起作用了!

Output:
Upper limit: 2147483647
Lower limit: -2147483648
于 2013-07-22T19:49:21.267 回答