C ++: Как я могу привести int к unsigned long и не менять биты? - PullRequest
4 голосов
/ 06 августа 2011

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 бит) и биты = 16.Цель состоит в том, чтобы замаскировать биты в памяти для значения и заменить их.

Кто-нибудь знает более простой способ?

Ответы [ 6 ]

7 голосов
/ 06 августа 2011

Если у вас есть поддержка C ++ 0x:

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

Я предполагаю, что вы настраиваете тип value, иначе это не имеет никакого смысла.

РЕДАКТИРОВАТЬ: сделать его более C ++ - с помощью static_cast вместо C-преобразования. Я полагаю, что это то, что заставило меня понизить голос.

5 голосов
/ 06 августа 2011

Если вы не возражаете против набора текста, на ум приходит класс черты:

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

Обновление: Еще проще, вы можете просто сделать кучу перегрузок:

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

2-е обновление: Вы, вероятно, должны сказать static_cast<T>(x) вместо (T)(x), если хотите быть еще более похожим на C ++.

2 голосов
/ 06 августа 2011

Как насчет союза?

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

};
1 голос
/ 08 августа 2011

Используя идею, выдвинутую "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 () теперь тоже шаблонизирован.

0 голосов
/ 06 августа 2011

Я считаю, что вы можете использовать побитовое И для получения желаемого результата.

unsigned long v2 = 0;
v2 = v2 | v1;
0 голосов
/ 06 августа 2011

Для приведения без изменения битов возьмите ссылку, а затем разыщите соответствующий тип:

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

Предполагается, что размеры одинаковы. Он имеет неопределенное поведение, если sizeof (int)! = Sizeof (unsigned long). Возможно, вы хотите unsigned int.

Редактировать: понял, что ответил на неправильный вопрос.

Boost type_traits имеет что-то (я думаю, что это make_unsigned), чтобы преобразовать тип int в неподписанную версию (если она подписана) и ничего не делать, если она не подписана.

...