2

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 から実際の型に変換したい。たとえば、コードの unsigned int64 変数に unsigned int32 を割り当てたい場合もあります。値が十分に大きい場合、符号なし int32 が int32_t として返されることを知っていると、この型では負の値として表され、uint64_t に static_cast すると、符号ビットが拡張されて uint64_t のすべての上位ビットが埋められます。これにより、意図したものとはまったく異なる符号なしの値が生成されます。

したがって、より大きな int 型またはより小さな int 型への正しい値へのキャストを処理するキャスト関数を作成しました。ただし、これは既知の問題であり、既存の解決策がある可能性があると思います。以下、関数です。これが改善される可能性があると思われる場合、またはより良い解決策がある場合はお知らせください (ただし、この関数は、私のユースケースで実際に必要なものよりも少し一般的なものにしています)。

編集:エンディアンに関してこれを移植可能にしました。

編集: 符号付き/符号なしの比較に関するコンパイラの警告を削除しました。

#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);
}
4

1 に答える 1