返回未知int类型的范围

时间:2014-07-22 14:07:01

标签: c

我被分配了一个问题,其中有人可能放入任何类型的有符号/无符号整数,并且两个函数必须使用按位运算等返回相应的最小值和最大值。

我正在尝试调整我所知道的关于两个补码的范围 - 范围由 - (2 n-1 )定义为(2 n-1 - 1)表示有符号值,0表示(2 n - 1表示无符号值。

但是,当我使用以下方法进行无符号时:

void create_minmax_unsigned() {
    unknownun exponent = (sizeof(unknownun) * 8) - 1;
    unknownun max = (1 << exponent) - 1;
    printf("The max is %d", max);
}

签名:

void create_minmax_signed() {
    unknowns exponent = (sizeof(unknowns) * 8) - 1;
    unknowns min = ((1 << exponent) + 1) - 1;
    unknowns max = (1 << exponent) - 1;
}

这种方法适用于char(un / s),short(un / s),int(un / s),long(un / s)但不长,即64位。

编辑:它实际上为所有int类型返回正确的位数。但是,对于long long,它没有显示正确的范围。

2 个答案:

答案 0 :(得分:0)

您不能只移动1 << (sizeof(signed type)*CHAR_BIT-1),因为这是未定义的行为(如果sizeof(signed type) >= sizeof(int))。另外,(x+1)-1是什么? (提示:x,除非x是INT_MAX,在这种情况下它是未定义的)。所以这不会给你一个负数,是吗?

答案 1 :(得分:0)

long long计算失败的原因是,分配的RHS计算为int,并且您尝试按int过大的值进行移位。

这个spiel逐步发展答案 - 只有最终的代码才真正可行。早期版本有各种问题需要解决,一次只能解决一个问题。

您需要将RHS强制转换为指定的类型:

void create_minmax_unsigned() {
    unknownun exponent = (sizeof(unknownun) * 8) - 1;
    unknownun max = ((unknownun)1 << exponent) - 1;
    printf("The max is %d", max);
}

void create_minmax_signed() {
    unknowns exponent = (sizeof(unknowns) * 8) - 1;
    unknowns min = (((unknowns)1 << exponent) + 1) - 1;
    unknowns max = ((unknowns)1 << exponent) - 1;
}

返回多个值时遇到问题。使用<inttypes.h>intmax_tuintmax_t强制转换可以使您的打印代码更加强大:

void create_minmax_unsigned() {
    unknownun exponent = (sizeof(unknownun) * 8) - 1;
    unknownun max = ((unknownun)1 << exponent) - 1;
    printf("The max is %" PRIuMAX, (uintmax_t)max);
}

void create_minmax_signed() {
    unknowns exponent = (sizeof(unknowns) * 8) - 1;
    unknowns min = (((unknowns)1 << exponent) + 1) - 1;
    unknowns max = ((unknowns)1 << exponent) - 1;
    printf("The max is %" PRIdMAX, (intmax_t)max);
    printf("The min is %" PRIdMAX, (intmax_t)min);
}

解决溢出问题

到目前为止,这使得您的计算基本不变;它只是确保值的类型正确。但是,您的计算容易受到数字溢出的影响,这可能(非常)非常糟糕 - 它会导致带符号整数类型的未定义行为和无符号类型的错误答案。

对于无法使用较大类型来覆盖罪恶的无符号类型,您需要仔细创建2 n -1,因为2<sup>n</sup>大于can存储,所以它看起来像0.当你减去1时,你会得到正确的答案,但你真的不需要移位/取幂。

void create_minmax_unsigned() {
    unknownun max = (unknownun)0 - 1;
    printf("The max is %" PRIuMAX, (uintmax_t)max);
}

对于签名类型,您不能使用2 n-1 - 1,因为无法表示2 n-1 。但是,您可以使用2 *(2 n-2 - 1)+ 1。负限制是减去一个值的值,导致:


未经测试的代码(错误):

void create_minmax_signed() {
    unknowns exponent = (sizeof(unknowns) * 8) - 2;
    unknowns max = 2 * ((unknowns)1 << exponent) + 1;
    unknowns min = -max - 1;
    printf("The max is %" PRIdMAX, (intmax_t)max);
    printf("The min is %" PRIdMAX, (intmax_t)min);
}

经测试的代码(不是那么多错误):

#include <inttypes.h>
#include <stdio.h>

typedef signed long long unknowns;
void create_minmax_signed(void);

void create_minmax_signed(void)
{
    unknowns exponent = (sizeof(unknowns) * 8) - 2;
    unknowns max = 2 * (((unknowns)1 << exponent) - 1) + 1;
    unknowns min = -max - 1;
    printf("The max is %+" PRIdMAX "\n", (intmax_t)max);
    printf("The min is %+" PRIdMAX "\n", (intmax_t)min);
}

int main(void)
{
  create_minmax_signed();
  return 0;
}

汇编:

/usr/bin/gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wold-style-declaration -Werror  mnx.c -o mnx

示例运行:

$ ./mnx
The max is +9223372036854775807
The min is -9223372036854775808
$