在C中查找short int变量的最大值

我正在研究K&R的练习2-1,目标是计算不同变量类型的范围,下面是我计算short int可以包含的最大值的函数:

 short int max_short(void) { short int i = 1, j = 0, k = 0; while (i > k) { k = i; if (((short int)2 * i) > (short int)0) i *= 2; else { j = i; while (i + j <= (short int)0) j /= 2; i += j; } } return i; } 

我的问题是这个函数返回的值是: -32768 ,这显然是错误的,因为我期待一个正值。 我无法弄清楚问题出在哪里,我使用相同的函数(在变量类型中有变化)来计算int可以包含的最大值,并且它有效…

我虽然问题可能是由ifwhile语句中的比较引起的,因此类型转换但没有帮助……

是什么原因引起了这个? 提前致谢!

编辑:感谢Antti Haapala的解释,符号位的溢出导致未定义的行为,而不是负值。

您不能使用这样的计算来推导有符号整数的范围,因为有符号整数溢出具有未定义的行为 ,并且最好使转换变窄导致实现定义的值或引发的信号。 正确的解决方案是使用 SHRT_MAXINT_MAX …。 通过算术推导出有符号整数的最大值是标准化C语言中的一个棘手问题,自1989年第一个标准出版以来就一直如此。

请注意,K&R的原始版本比C的标准化提前了11年,甚至第二个版本 – “ANSI-C”版本早于最终标准并且与它有所不同 – 它们是针对一种几乎不是的语言编写的,但不完全,完全不同于今天的C语言。

您可以轻松地对无符号整数执行以下操作:

 unsigned int i = -1; // i now holds the maximum value of `unsigned int`. 

根据定义,您无法通过使用相同类型的变量来计算C中类型的最大值。 它根本没有任何意义。 当它“越过顶部”时,该类型将溢出。 在有符号整数溢出的情况下,行为是未定义的,这意味着如果您尝试它将会遇到一个主要错误。

正确的方法是从limits.h中检查SHRT_MAX

另一种更有问题的方法是创建unsigned short的最大值然后将其除以2.我们可以通过对值0进行按位求逆来创建最大值。

 #include  #include  int main() { printf("%hd\n", SHRT_MAX); // best way unsigned short ushort_max = ~0u; short short_max = ushort_max / 2; printf("%hd\n", short_max); return 0; } 

关于您的代码的一个注释:

诸如((short int)2*i)>(short int)0类的强制转换是完全多余的。 C中的大多数二元运算符(例如*>实现了一种称为“通常的算术转换”的东西,这是一种隐式转换和平衡表达式类型的方法。 这些隐式转换规则将默默地使两个操作数类型为int尽管你的转换。

在比较期间你忘了转换为short int

好吧,在这里我假设计算机将通过改变为负整数来处理整数溢出行为,因为我相信你已经假设写了这个程序。

输出32767的代码:

 #include  #include  #include  short int max_short(void) { short int i = 1, j = 0, k = 0; while (i>k) { k = i; if (((short int)(2 * i))>(short int)0) i *= 2; else { j = i; while ((short int)(i + j) <= (short int)0) j /= 2; i += j; } } return i; } int main() { printf("%d", max_short()); while (1); } 

增加了两个演员