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.
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.
Does anyone know an easier way?
You can convert an int to an unsigned int . The conversion is valid and well-defined. Since the value is negative, UINT_MAX + 1 is added to it so that the value is a valid unsigned quantity. (Technically, 2N is added to it, where N is the number of bits used to represent the unsigned type.)
Conversion from signed to unsigned does not necessarily just copy or reinterpret the representation of the signed value. Quoting the C standard (C99 6.3. 1.3): When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
An unsigned data type stores only positive values. It takes a size of 64 bits. A maximum integer value that can be stored in an unsigned long long int data type is 18, 446, 744, 073, 709, 551, 615, around 264 – 1(but is compiler dependent).
To convert a signed integer to an unsigned integer, or to convert an unsigned integer to a signed integer you need only use a cast. For example: int a = 6; unsigned int b; int c; b = (unsigned int)a; c = (int)b; Actually in many cases you can dispense with the cast.
Assuming you have C++0x support:
#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.
EDIT: making it more C++-ish by using static_cast
instead of a C cast. I suppose that's what got me a downvote.
If you don't mind the typing, a trait class comes to mind:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With