首页 > 解决方案 > abs(无符号)的意外行为

问题描述

自从写了一个关于 abs() 的程序(它遇到了一个断言)一年多之后,我偶然发现了一个非常疯狂的错误。我会省略你的细节,我会在这里告诉你我不明白的东西:

xubuntu_x64 上的 gcc 版本 7.5.0:

#include <stdlib.h>

int _test_abs(int x) {
    return abs((unsigned)x);
}

尝试编译它,编译器开始抱怨“对 abs(unsigned int) 的调用不明确”,并列出候选 abs(int)、abs(long)、abs(float),你可以命名它(但没有 abs(unsigned ) 出现在任何地方,这是预期的 - 否则不会有歧义)

现在用 <cstdlib> 替换 <stdlib.h> 并且一切都可以编译,没有错误。在这种情况下,它到底怎么不抱怨模棱两可?<cstdlib> 中的某处是否声明了 abs(unsigned)?我在 <cmath> 中找不到有关此类签名的任何信息

<math.h> 与 <cmath> 也是如此。

有人能告诉我这个吗?

PS我的错误是什么:我经常在涉及无符号数量时使用无符号,但我接受在我的代码中使用表达式,例如(unsig1-unsig2),它可能偶尔为负(即unsig2略大于unsig1),但是我直接使用 abs(unsig1-unsig2) 而无需转换为 abs((int)(unsig1-unsig2) 因为它应该没问题,当调用 abs(int) 时值将转换为'int',而 abs 应该确实返回正确的绝对值。我不知道的是,我的程序中实际上从未调用过 abs(int),而是使用了 abs(float) 版本(或 double 或 long double 或其他),并且在此如果将 unsig2 略 > unsig1 的无符号表达式 (unsig1-unsig2) 转换为浮点数的结果是一个巨大的无符号值而不是一个小的 "负无符号”!底线,我期待来自 abs(int) 的行为,但实际上却调用了 abs(float) 并给了我疯狂的意外结果。

PPS fwiw,我在小“调查”期间遇到的一篇有趣的文章,显然 abs() 是一团糟:https ://developers.redhat.com/blog/2016/02/29/why-cstdlib-is-more -比你想象的复杂/

标签: math.hcmath

解决方案


经过一些检查员clouseau 侦探工作后,我想出了一个可能的答案:也许 <cmath> 和 <cstdlib> 在全局命名空间中只定义“abs(int)”,而完整的声明集(int + 重载)是专门定义的在 'std::"中。如果您在上面的代码中使用 <cmath>/<cstdlib> 并将调用更改为“std::abs()”,那么您会得到“模糊”错误(即在包含 <cmath>/<cstdib> 的“std::”命名空间,然后找到 int 和重载版本,因此出现错误)。

有谁知道这是否确实如此(w/链接到您的信息来源)?

PS无论如何,很明显它是一团糟,因为即使这个答案是正确的,也没有这个实现的标准要求(至少到并包括c ++ 11,请参阅OP中的链接)


推荐阅读