计算C中数据类型的范围

我正在研究K&R第二版,并且无法弄清楚为什么我会得到一定的结果。 我正在解决的问题是计算数据类型的上限和下限。 特别:

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

我已经了解了按位运算符和两个赞美,并且我认为应该对签名数据类型有效,但是它适用于对我没有任何意义的无符号数据类型。 这是代码:

#include  main() { signed int i; i = ~0; i >>= 1; printf("Upper limit: %d\n", i); printf("Lower limit: %d\n", -i -1); } 

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

 ~0 == 11111111111111111111111111111111 

,和

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

知道我哪里错了吗?

输出:

  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和所有值位0(对于前两个),或者符号位和所有值位1(对于1’补码)的值是否是陷阱表示或正常值。 在符号和幅度以及1’补码的情况下,如果该表示是正常值,则称为负零。

    您的理解:

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

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

    对于unsigned shift,请尝试以下操作:

    ~0U >> 1 == 011111111111111111111111111111111

    注意后缀U表示未签名。

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

通过使用%d您可以将您的值视为已signed以通过printf继续。

你可以使用%u代替。

添加

正如Magn3s1um指出的那样,你不需要为你的特定任务指定signedunsignedprintf将为你完成所有工作。

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

也就是说,〜0 >> 1仍然是〜0,因为移位符号延伸。

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

您可能对limits.h和float.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 | +------------+------------------------------------------------------------------+--------------------------------+ 

当您对i执行位移时,编译器会看到i是有符号数,并执行算术右移。 您似乎希望该行代码执行逻辑右移。

改变线

i >>= 1;

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

然后它的作品!

 Output: Upper limit: 2147483647 Lower limit: -2147483648