计算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.
知道我哪里错了吗?
输出:
-
注意:
“在表达式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
表示未签名。 -
第二个printf :
因为i
是-1
,所以在第二个表达式-i - 1
==- (-1) - 1
==1 - 1
==0
所以输出为零:0
。
通过使用%d
您可以将您的值视为已signed
以通过printf
继续。
你可以使用%u
代替。
添加
正如Magn3s1um指出的那样,你不需要为你的特定任务指定signed
和unsigned
, printf
将为你完成所有工作。
您的编译器将>>实现为算术移位。 因此,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