使无符号的 int 值成为有符号的 int 值并返回

Make signed int value from unsigned int value and back

本文关键字:int 符号 返回 无符号      更新时间:2023-10-16

我需要将无符号整数序列转换为有符号整数序列,并保持元素的顺序。

理想情况下,我需要这样的函数

template <typename T>
std::make_signed_t<T> MakeSigned(T val);
template <typename T>
std::make_unsigned_t<T> MakeUnsigned(T val);

实施它们的正确方法是什么?

编辑1:

函数 MakeSigned 和 MakeUnsigned 应满足以下条件:

对于给定的参数对 a、b 和返回值 a1、b1,如果 a <= b,则 a1 <= b1。

并且对于给定的签名

MakeSigned(MakeUnsigned(a)) == a

编辑2

MakeSigned 这样做(对于给定的类型uint8_t、uint16_t、uint32_t uint64_t(:

0 => INT_MIN
UINT_MAX => INT_MAX

制作未签名:

INT_MIN => 0
INT_MAX => UINT_MAX

一种解决方案是在映射到/从unsigned类型映射时减去/添加偏差项std::numeric_limits<Signed>::min()。计算必须使用无符号算术完成,该算术包装不会产生未定义的行为:

#include <iostream>
#include <type_traits>
#include <limits>
#include <cstdint>
template<typename T>
typename std::enable_if_t<std::is_unsigned_v<T>, std::make_signed<T>>::type map_to_signed(T val) {
using U = std::make_signed_t<T>;
return val + std::numeric_limits<U>::min(); // Wrapping unsigned addition. 
}
template<typename T>
typename std::enable_if_t<std::is_signed_v<T>, std::make_unsigned<T>>::type map_to_unsigned(T val) {
using U = std::make_unsigned_t<T>;
return static_cast<U>(val) - std::numeric_limits<T>::min(); // Wrapping unsigned subtraction.
}
int main() {
std::cout << map_to_signed(0u) << 'n';
std::cout << map_to_unsigned(map_to_signed(0u)) << "nn";
std::cout << std::numeric_limits<int>::max() << 'n';
std::cout << map_to_unsigned(std::numeric_limits<int>::max()) << 'n';
std::cout << map_to_signed(map_to_unsigned(std::numeric_limits<int>::max())) << "nn";
std::cout << std::numeric_limits<unsigned>::max() << 'n';
std::cout << map_to_signed(std::numeric_limits<unsigned>::max()) << 'n';
std::cout << map_to_unsigned(map_to_signed(std::numeric_limits<unsigned>::max())) << "nn";
std::cout << std::numeric_limits<uint64_t>::max() << 'n';
std::cout << map_to_signed(std::numeric_limits<uint64_t>::max()) << 'n';
std::cout << map_to_unsigned(map_to_signed(std::numeric_limits<uint64_t>::max())) << "nn";
}

输出:

-2147483648
0
2147483647
4294967295
2147483647
4294967295
2147483647
4294967295
18446744073709551615
9223372036854775807
18446744073709551615

我会简单地翻转符号位:

template <typename T>
std::make_signed_t<T> MakeSigned(T val)
{
return val ^ (1u << (sizeof(T) * 8 - 1));
}
template <typename T>
std::make_unsigned_t<T> MakeUnsigned(T val)
{
return val ^ (1u << (sizeof(T) * 8 - 1));
}

有趣的是,您没有要求这些函数保留ab的值。这很好,因为如果是这样,那么它们将无法实施。

因此,您希望在转换时"偏移"值。

所以int(0)变得unsigned(std::numeric_limits<int>::max()+1)unsigned(0)变得std::numeric_limits<int>::min()

有了这个,以及Maxim的结构,你应该能够编写你需要的函数。

哦,如果你使用INT_MININT_MAX而不是numeric_limits,你会失败的。