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

Finding maximum value of a short int variable in C

我在做K&R的Exercise 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 ... of <limits.h>。通过算术推导 有符号整数 的最大值是标准化 C 语言中的一个技巧问题,自 1989 年第一个标准发布以来一直如此。

请注意,K&R 的原始版本早于 C 的标准化 11 年,甚至 2nd 版本 - "ANSI-C" 版本 早于 最终确定的标准并且与它有些不同 - 它们是为一种语言编写的,这种语言与当今的 C 语言几乎不同,但也不完全不同。

不过对于无符号整数,您可以轻松做到这一点:

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

你在比较时忘记转换为 short int

好的,这里我假设计算机会通过变成负整数来处理整数溢出行为,我相信你在编写这个程序时已经假设了。

输出 32767 的代码:

#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
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);
}

增加了 2 个施法

根据定义,您不能通过使用完全相同类型的变量来计算 C 中类型的最大值。这根本没有任何意义。当它变为 "over the top" 时,类型将溢出。在有符号整数溢出的情况下,行为是未定义的,这意味着如果您尝试这样做,您将遇到一个重大错误。

正确的做法是简单地检查 limits.h 和 SHRT_MAX

另一种更值得怀疑的方法是创建 unsigned short 的最大值,然后将其除以 2。我们可以通过对值 0 进行按位反转来创建最大值。

#include <stdio.h>
#include <limits.h>

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 中的大多数二元运算符,例如 *> 实现了一种叫做 "the usual arithmetic conversions" 的东西,这是一种隐式转换和平衡表达式类型的方法。这些隐式转换规则将默默地使两个操作数类型 int 尽管您进行了强制转换。