math.h - 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 -比你想象的复杂/
解决方案
经过一些检查员clouseau 侦探工作后,我想出了一个可能的答案:也许 <cmath> 和 <cstdlib> 在全局命名空间中只定义了“abs(int)”,而完整的声明集(int + 重载)是专门定义的在 'std::"中。如果您在上面的代码中使用 <cmath>/<cstdlib> 并将调用更改为“std::abs()”,那么您会得到“模糊”错误(即在包含 <cmath>/<cstdib> 的“std::”命名空间,然后找到 int 和重载版本,因此出现错误)。
有谁知道这是否确实如此(w/链接到您的信息来源)?
PS无论如何,很明显它是一团糟,因为即使这个答案是正确的,也没有这个实现的标准要求(至少到并包括c ++ 11,请参阅OP中的链接)
推荐阅读
- ruby-on-rails - Has_Many_Through 未能推动许多人通过
- java - Java Spring Webflux WebClient - 使用 HTTP2 发送 http 请求
- java - 如何使正则表达式提前匹配一位和两位数字?
- leaflet - Leaflet marker.cluster 弹出传单ajax加载的geojson数据
- wordpress - 如何在本地机器上访问 Word Press (Elementor) 代码
- javascript - 第一次在 JS 中使用 API。需要帮助将数组填充到表头的内部文本中
- heroku - 如何在 Heroku 上配置 API
- react-native - 绝对定位时 FlatList 滚动中断
- ruby-on-rails - Guard / Minitest 失败 - 'capybara 不是捆绑包的一部分。将它添加到您的 Gemfile 中。
- gcc - 如何在 miniconda 环境中升级 gfortran