按位整数转换
Bitwise Integer Conversion
我必须使用返回int32_t的API。但实际值可能是较小的有符号/无符号类型。要知道API返回ENUM值的确切类型。它看起来像这样:
typedef enum Int{
Int8,
Int16,
Int32,
Uint8,
Uint16,
Uint32
}IntT;
typedef struct{
IntT (*getType)();
void (*getInt)(int32_t* out);
}IntegerT;
我想通过知道枚举值将值从int32_t转换为实际类型。有时我甚至想在代码中将无符号int32变量赋值给无符号int64变量。知道如果值足够大,unsigned int32返回为int32_t,那么它在该类型中表示为负值,如果我只是将其静态转换为uint64_t,那么符号位将扩展以填充uint64_t中所有较高的位,从而产生完全不同的unsigned值。
因此,我编写了一个强制转换函数,它应该负责将较大的int类型或较小的int类型强制转换为正确的值。然而,我觉得这可能是一个已知的问题,可能已经存在解决方案。下面是函数。请告知如果你认为这可以改进,或者如果有一个更好的解决方案(我已经使这个函数比我真正需要我的用例更通用)。编辑:使此可移植关于Endianness。
编辑:删除编译器对有符号/无符号比较的警告。
#include <limits>
#include <boost/static_assert.hpp> //BOOST_STATIC_ASSERT
#include <stdexcept>
#include <cstring>
#include <boost/type_traits/make_unsigned.hpp>
namespace Detail
{
/** This a implementation helper class for bitwise_int_cast function */
template<bool IsToTypeSigned, bool IsFromTypeSigned>
class Converter
{
public:
template<typename ToIntType, typename FromIntType>
ToIntType convert(FromIntType from) {
BOOST_STATIC_ASSERT(sizeof(from) == 0); //This prevents this generic implementation being compiled
return from;
}
};
/** From signed to signed */
template<>
template<typename ToIntType, typename FromIntType>
ToIntType Converter<true, true>::convert(FromIntType from)
{
BOOST_STATIC_ASSERT(std::numeric_limits<ToIntType>::is_signed && std::numeric_limits<FromIntType>::is_signed);
if((from < std::numeric_limits<ToIntType>::min()) ||
(from > std::numeric_limits<ToIntType>::max())
) {
throw std::runtime_error("Integer overflow in casting from large signed rvalue into smaller signed lvalue");
}
return static_cast<ToIntType>(from);
}
/** From signed to unsigned */
template<>
template<typename ToIntType, typename FromIntType>
ToIntType Converter<false, true>::convert(FromIntType from)
{
BOOST_STATIC_ASSERT(!std::numeric_limits<ToIntType>::is_signed && std::numeric_limits<FromIntType>::is_signed);
typedef typename boost::make_unsigned<FromIntType>::type unsignedType;
unsignedType unsignedIn = from;
if(std::numeric_limits<FromIntType>::digits < std::numeric_limits<ToIntType>::digits) {
if(from < 0) {
return unsignedIn;
}
} else {
if(from > 0) {
if (unsignedIn > std::numeric_limits<ToIntType>::max()) {
throw std::runtime_error("Integer overflow in casting from large signed rvalue into smaller unsigned lvalue");
}
} else if (from < 0) {
throw std::runtime_error("Integer overflow in casting from large signed rvalue into smaller unsigned lvalue");
}
}
return unsignedIn;
}
/** From unsigned to signed */
template<>
template<typename ToIntType, typename FromIntType>
ToIntType Converter<true, false>::convert(FromIntType from)
{
BOOST_STATIC_ASSERT(std::numeric_limits<ToIntType>::is_signed && !std::numeric_limits<FromIntType>::is_signed);
if(std::numeric_limits<ToIntType>::digits < std::numeric_limits<FromIntType>::digits) {
typename boost::make_unsigned<ToIntType>::type allBitsSet = -1; //e.g. 0xFFFF
if( from > allBitsSet) {
throw std::runtime_error("Integer overflow in casting from large unsigned rvalue into smaller signed lvalue");
}
}
return static_cast<ToIntType>(from);
}
/** From unsigned to unsigned */
template<>
template<typename ToIntType, typename FromIntType>
ToIntType Converter<false, false>::convert(FromIntType from)
{
if(from > std::numeric_limits<ToIntType>::max()) {
throw std::runtime_error("Integer overflow in casting from large unsigned rvalue into smaller unsigned lvalue");
}
return static_cast<ToIntType>(from);
}
}
/**
* This cast only cares about integer sizes not sign mismatch
* works only on two's complement (Big or Little Endian) Machines
*/
template<typename ToIntType, typename FromIntType>
inline ToIntType bitwise_int_cast(FromIntType from)
{
BOOST_STATIC_ASSERT(std::numeric_limits<ToIntType>::is_integer && std::numeric_limits<FromIntType>::is_integer);
Detail::Converter<std::numeric_limits<ToIntType>::is_signed, std::numeric_limits<FromIntType>::is_signed> converter;
return converter.template convert<ToIntType>(from);
}
您可以使用联合:
union mergeint_t
{
int8_t int8;
int16_t int16;
int32_t int32;
int64_t int64;
//..
};
赋值给int32:
mergeval.int32=yourFunctionReturningInt32();
然后从联合的适当成员访问该值。
if (type==INT8_T) {
int8val = mergeint.int8;
}
//编辑:
我测试了这个方法,因为我不确定字节顺序是否会正确地保持在这里。在我的Linux上,下面的程序可以正常工作:
int main() {
union mergeint_t mergeval;
mergeval.int64=11;
printf("mergeval int8=[%d]nn", mergeval.int8);
}
给出输出:mergeval int8=[11]
//EDIT2:
是的,此方法可能不适用于Big Endian机器。我没有,所以我不能测试它。对不起,我之前没有告诉你。我想如果我在上面的疑问中提到了字节顺序,那么或多或少就会清楚这可能是一个有限的解决方案。
相关文章:
- 努力将整数转换为链表。不知道我在这里做错了什么
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 如何在C++中将整数转换为其数字数组
- 尝试将字符串/字符转换为整数会产生意外结果
- 如何使用C++将字符串中的字符转换为整数变量
- 如何将整数字符串转换为整数的二维向量?
- 如果整数与指针大小相同,则重新解释将整数转换为指针双射是否具有双射作用?
- 使用 "stringstream " 将字符串转换为整数
- 将字符串转换为浮点数或整数,而无需使用内置函数(如 atoi 或 atof)
- 如何检测 std::vector::emplace_back 上的隐式转换损失整数精度
- 如何防止双精度值到整数的隐式转换
- 为什么此指针值不能转换为整数的规则是什么?
- 如何解决隐式转换丢失整数精度:'size_t'(又名"无符号长")到'int'警告?
- 在 C++ 中将整数数组转换为位集表示形式的最佳方法?
- 为什么在将 void 指针转换为整数指针时出现分段错误
- 将字符串(可以是十进制字符串或十六进制字符串)转换为整数C++
- 整数类型应该显式转换(例如"int"到"无符号")还是只会增加混乱?
- 如何使用 STL 算法将整数向量转换为字符串向量?
- 无法将"整数 (*)[m]"转换为"整数 (*)[100000]
- 静态强制转换允许转换对象指针,但不允许转换整数