为什么stdlib.h的abs()系列函数返回有符号值?

时间:2009-10-23 01:26:53

标签: c math std

这一点的负面含义见手册页:

  

NOTES          试图取最负整数的绝对值是   不          定义

这背后的原因是什么,对于想要避免未定义行为的人来说,最佳追索权是什么?我是否必须采取以下措施:

unsigned uabs(signed val) {
    return val > 0
        ? val
        : (val == 1U << ((sizeof(val) * 8) - 1))
            ? -1U
            : -val;
}

(故意hacky强调对stdlib的不满; - )

实施例

假设您有一个4位有符号值(为了便于理解)。 unsigned max是15,signed(正)max是7,signed(负)min是-8,所以abs(-8)不适合有符号值。当然,您可以将其表示为-8,但随后对结果的除法和乘法不会按预期工作。

2 个答案:

答案 0 :(得分:19)

这个问题的真正答案在于类型推广规则。

如果我将算术运算符应用于unsigned intint,则int参数将提升为unsigned,结果也为unsigned }。

如果abs()函数返回unsigned,那么当它在表达式中使用时会导致其他类型的类型提升,这会导致意外结果。例如,此代码:

if (abs(-1) * -1 < 0)
    printf("< 0\n");
else
    printf(">= 0\n");

会打印“&gt; = 0”,这是许多人不愿意的。不能使用单一值INT_MIN的权衡可能看起来没问题。

答案 1 :(得分:0)

为什么它会使用无符号空格返回一个值?

让我们考虑8位有符号和无符号数。如果你有-128,结果是未定义的......我猜stdlib不想放慢那么多。如果您认为您可能拥有该范围内的数字,那么您需要使用其他内容。

如果您认为签名字符中的值可能大于127,那么您就错了。

因此,值不必能够保存大于127的值,并且保持签名不会丢失任何内容。如果你想将它转换为无符号,请继续。因为它曾经是一个有符号整数,所以你将再次进行有符号数学运算的几率很高。就我个人而言,我认为我更喜欢这种类型保持签名,因为我很少想要处理无符号并且我没有做位操作。

但也许其他人可以从标准委员会那里挖掘一些笔记。