C++:如何将 int 转换为 unsigned long 并且不更改任何位?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6963534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 21:02:21  来源:igfitidea点击:

C++: How do I cast an int to an unsigned long and not change any bits?

c++castingbit-manipulation

提问by Michael Fitzpatrick

C++: How do I cast an int to an unsigned long and not change any bits? I want to pack and unpack values into memory. The word size is 64 bits.

C++:如何将 int 转换为 unsigned long 并且不更改任何位?我想将值打包和解包到内存中。字长为 64 位。

This snippet illustrates the problem:

这段代码说明了这个问题:

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

The simple solution is:

简单的解决方法是:

unsigned long v2=(unsigned int)v1; // 0x00fe

However, this code is in a template where the target type is a parameter, so I had to resort to this:

但是,此代码位于目标类型是参数的模板中,因此我不得不求助于:

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;

Assume, for example, the type for "value" is an int (16 bits) and bits=16. The goal is to mask the bits in memory for value and replace them.

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

Does anyone know an easier way?

有谁知道更简单的方法?

采纳答案by Michael Fitzpatrick

Using the idea put forth by "Kerrek SB" I came up with a solution.

使用“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;
}

Using this concept I was able to make other improvements to the code. For example, the call to vectorItemMask() is now templateized also.

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

回答by MSN

Assuming you have C++0x support:

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

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

I'm assuming that you are parameterizing on the type of value, otherwise this doesn't make any sense.

我假设您正在对 的类型进行参数化value,否则这没有任何意义。

EDIT: making it more C++-ish by using static_castinstead of a C cast. I suppose that's what got me a downvote.

编辑:通过使用static_cast而不是 C强制转换使其更像 C++ 。我想这就是让我投反对票的原因。

回答by Kerrek SB

If you don't mind the typing, a trait class comes to mind:

如果你不介意打字,你会想到一个 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 ... */

Usage:

用法:

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

Update:Even simpler, you could just make a bunch of overloads:

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

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

2nd update:You should probably say static_cast<T>(x)rather than (T)(x)if you want to be even more C++-like.

第二次更新:您可能应该说,static_cast<T>(x)而不是(T)(x)您是否想要更像 C++。

回答by outmind

How about union?

工会怎么样?

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;}

};

回答by Puppy

I believe that you could use a bitwise-AND to get the desired result.

我相信您可以使用按位与来获得所需的结果。

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

回答by Foo Bah

To cast without changing bits, take a reference and then dereference with appropriate type:

要在不更改位的情况下进行转换,请获取引用,然后使用适当的类型取消引用:

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

This assumes the sizes are the same. It has undefined behavior if sizeof(int) != sizeof(unsigned long). You probably want unsigned int.

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

Edit: realized i answered wrong question.

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

Boost type_traits has something (i believe it is make_unsigned) to convert an int type to the unsigned version (if it is signed) and do nothing if it is unsigned.

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