简介:
我们假设以下代码
#include <cmath>
#include <limits>
int main(int, char**)
{
long long v = std::numeric_limits<long long>::min();
unsigned long long av = std::abs(v);
return 0;
}
这里的问题是
std::abs(v)
的返回类型是 long long
并且 std::numeric_limits<long long>::min()
的绝对值不能用 long long
表示(不确定标准是否要求,但至少对于我的平台)。我相信里面std::abs(v)
我已经有符号整数溢出,这就是UB。
简单的解决方案应该是
unsigned long long myabs(long long v)
{
if (v == std::numeric_limits<long long>::min())
return static_cast<unsigned long long>(std::numeric_limits<long long>::max()) + 1;
return static_cast<unsigned long long>(abs(v));
}
总结:
是否有更好的方法(标准或非标准)来获取
std::numeric_limits<long long>::min()
的绝对值?
在这里你可以找到一些关于C的建议,但我正在寻找C++解决方案。
template <std::signed_integral integer>
constexpr std::make_unsigned_t<integer>
uabs(integer const i){
constexpr static auto sign
= std::bit_cast< std::make_unsigned_t<integer>>
( std::numeric_limits<integer>::min() );
auto const value
= std::bit_cast<decltype(sign)>(i);
return (value > sign)
? (static_cast<decltype(sign)>(0u) - value)
: (value);
};
这适用于 2 的补码签名平台。对于任何有符号整数类型。