如何将int型转换为unsigned long型而不改变任何位?



c++:如何将int型转换为unsigned long型而不改变任何位?我想将值打包和解包到内存中。字长为64位。

下面的代码片段说明了问题:

int v1 = -2; // 0xfe
unsigned long v2=(unsigned long)v1; // 0xfffe, I want 0x00fe

简单的解决方案是:

unsigned long v2=(unsigned int)v1; // 0x00fe
然而,这段代码是在一个模板中,其中目标类型是一个参数,所以我不得不采用如下方式:
uint64 target = mem[index] & mask;
uint64 v;
if (value < 0) {
    switch (bits) {
    case 8:
        v = (uint8)value;
        break;
    case 16:
        v = (uint16)value;
        break;
    case 32:
        v = (uint32)value;
        break;
    }
} else {
    v = value;
}
v = v << lShift;
target |= v;
mem[index] = target;

例如,假设"value"的类型为int(16位),且bits=16。目标是屏蔽内存中的值位并替换它们。

有谁知道更简单的方法吗?

假设您有c++ 0x支持:

#include <type_traits>
v= static_cast<std::make_unsigned<decltype(value)>::type>(value);

我假设你是在参数化value的类型,否则这没有任何意义。

编辑:通过使用static_cast而不是C强制转换,使其更像c++。我想这就是我被拒绝的原因。

如果你不介意输入,那么你会想到一个trait类:

template <typename IType> struct ToULong;
template <> struct ToULong<signed char>
{
  static inline unsigned long int get(signed char c) { return (unsigned char)(c); }
};
template <> struct ToULong<signed short int>
{
  static inline unsigned long int get(signed short int c) { return (unsigned short int)(c); }
};
/* ... signed int, signed long int, signed long long int ... */

用法:

template <typename IType>
struct Foo
{
  unsigned lont int get_data() const { return ToULong<IType>::get(m_data); }
private:
  IType m_data;
}

Update:更简单,你可以做一堆重载:

unsigned long int toULong(            char c) { return (unsigned      char)(c); }
unsigned long int toULong(signed      char c) { return (unsigned      char)(c); }
unsigned long int toULong(signed short int c) { return (unsigned short int)(c); }
unsigned long int toULong(signed       int c) { return (unsigned       int)(c); }
unsigned long int toULong(signed  long int c) { return (unsigned  long int)(c); }

第二次更新:如果你想更像c++,你可能应该说static_cast<T>(x)而不是(T)(x)

联合呢?

union u1 {
    short int si;
    unsigned long int uli;
    unsigned long int stub;
    operator unsigned long int () {return uli;};
public:
    u1(short int nsi) : stub(0) {si = nsi;}
};

我相信您可以使用位与运算来获得期望的结果。

unsigned long v2 = 0;
v2 = v2 | v1;

根据"Kerrek SB"提出的想法,我想出了一个解决方案。

template <typename Tint> uint64 ToMemdata(Tint value) {
    return (uint64)value;};
template <> uint64 ToMemdata<int8>(int8 value) {
    return (uint64)((uint8)value);};
template <> uint64 ToMemdata<int16>(int16 value) {
    return (uint64)((uint16)value);};
template <> uint64 ToMemdata<int32>(int32 value) {
    return (uint64)((uint32)value);};
template <> uint64 ToMemdata<int64>(int64 value) {
    return (uint64)((uint64)value);};
template <typename Tint> void packedWrite(Tint value, int vectorIndex, uint64* pData) {
    uint64 v = ToMemdata(value);
    // This call eliminates a run time test for minus and a switch statement
    // Instead the compiler does it based on the template specialization
    uint64 aryix, itemofs;
    vectorArrayIndex(vectorIndex, &aryix, &itemofs); // get the memory index and the byte offset
    uint64 mask = vectorItemMask(itemofs); // get the mask for the particular byte
    uint64 aryData = pData[aryix]; // get the word in memory
    aryData &= mask; // mask it
    uint64 lShift = (uint64)(itemofs * sizeof(Tint) * 8); 
    uint64 d = v << lShift; // shift the value into the byte position
    aryData |= d; // put the value into memory
    pData[aryix] = aryData;
}

使用这个概念,我能够对代码进行其他改进。例如,对vectorItemMask()的调用现在也被模板化了。

要在不改变位的情况下进行强制转换,请获取引用,然后使用适当的类型解除引用:

int v1 = -2; // 0xfe
unsigned long v2=*(unsigned long *)&v1;

假设大小相同。如果sizeof(int) != sizeof(unsigned long),则具有未定义的行为。你可能需要unsigned int

编辑:意识到我回答错了问题。

Boost type_traits有一些东西(我相信它是make_unsigned)将int类型转换为无符号版本(如果它是有符号的),如果它是无符号的,什么也不做。

相关内容

最新更新