【问题标题】:Why does stdlib.h's abs() family of functions return a signed value?为什么 stdlib.h and() 系列函数返回有符号值?
【发布时间】:2010-12-09 07:37:18
【问题描述】:

手册页中指出了这一点的负面影响:

注意事项 试图取最大负整数的绝对值是 不是 已定义。

这背后的原因是什么?对于想要避免未定义行为的人来说,最好的办法是什么?我是否必须求助于:

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

(为了强调对 stdlib 的不满而故意弄巧成拙 ;-)

示例

假设您有一个 4 位有符号值(为了便于理解)。无符号最大值为 15,有符号(正)最大值为 7,有符号(负)最小值为 -8,因此 abs(-8) 不适合有符号值。当然,您可以将其表示为 -8,但结果的除法和乘法无法按预期工作。

【问题讨论】:

    标签: c math std


    【解决方案1】:

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

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

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

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

    会打印 ">= 0",这是很多人不喜欢的。不能使用单个值 INT_MIN 的折衷可能看起来没问题。

    【讨论】:

    • +1 好点,从签名到未签名的提升是一个非常有力的论据:)
    • 我可以买这个——类型提升很复杂,你不能责怪任何人希望所有东西都适合一个签名值。我想如果我能回到过去与委员会争论,我会说 abs 应该尽可能准确,并且 C 程序员已经必须知道如何处理表达式中的函数返回类型和类型提升,但我离开了我的一次在公共汽车上的时光机。
    • 好吧,另一种说法是,如果您已经在对有符号值进行算术运算,则需要检查下溢/溢出 - 这只是意味着您需要检查一个操作是否不会如果您要将其传递给abs(),则生成低于-INT_MAX 而不是INT_MIN 的结果。
    • 同意这是一般情况下的反论点。只是一个挑剔的澄清:如果它是int 的味道,你永远不必检查是否低于INT_MIN,所以在unsigned abs(signed) 的这种特殊情况下,你根本不需要在调用之前检查参数。跨度>
    • 这就是为什么我没有说你会检查一个值是否低于INT_MIN——而是你需要检查一个计算的result不会be (因为这会导致有符号溢出,这是未定义的行为)。例如,如果您正在计算 a - b,在正常情况下您需要验证 a &gt;= INT_MIN + b - 如果您要将其传递给 abs(),则需要将其更改为 a &gt; INT_MIN + b
    【解决方案2】:

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

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

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

    因此,该值没有必要能够保持大于 127 的值,并且保持签名不会丢失任何内容。如果您想将其转换为未签名,请继续。由于它曾经只是一个有符号整数,因此您很有可能再次进行有符号数学运算。就个人而言,我认为我更喜欢保持有符号类型,因为我实际上想要处理无符号并且我不进行位操作的情况非常罕见。

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

    【讨论】:

    • 如果abs 函数返回unsigned,定义abs(INT_MIN) 不会有问题——它不会使计算速度变慢——标准的底层否定操作仍然可以正常工作.这不是问题——真正的问题是类型提升。
    • 它应该不会更慢——绝对值的常见组装顺序是 ((x + y) ^ y),它适用于最大负值导致无符号字。
    • 我的意思是,你唯一的缺点是如果你在 INT_MIN,那真的很少见。我以“个人”开头的句子暗示了 caf 提供的“类型”解释。我回答的主要目的是试图让人们相信他们并没有失去太多。
    猜你喜欢
    • 2023-03-02
    • 1970-01-01
    • 2020-08-11
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 2016-06-15
    相关资源
    最近更新 更多