Как я преобразовываю между значениями с прямым порядком байтов и с обратным порядком байтов в C++?

Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int:

int x;
x = 10;

В этом примере переменная x является int, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.

Но когда вы пытаетесь объявить ссылочный тип, произойдет что-то другое. Возьмите следующий код:

Integer num;
num = new Integer(10);

Первая строка объявляет переменную с именем num, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».

Во второй строке ключевое слово new используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования . (точка).

Exception, о котором вы просили, возникает, когда вы объявляете переменную, но не создавали объект. Если вы попытаетесь разыменовать num. Перед созданием объекта вы получите NullPointerException. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что «num не может быть инициализирован», но иногда вы пишете код, который непосредственно не создает объект.

Например, вы можете имеют следующий метод:

public void doSomething(SomeObject obj) {
   //do something to obj
}

В этом случае вы не создаете объект obj, скорее предполагая, что он был создан до вызова метода doSomething. К сожалению, этот метод можно вызвать следующим образом:

doSomething(null);

В этом случае obj имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.

Альтернативно, там могут быть случаи, когда цель метода заключается не только в том, чтобы работать с переданным в объекте, и поэтому нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething может быть записано как:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj != null) {
       //do something
    } else {
       //do something else
    }
}

Наконец, Как определить исключение & amp; причина использования Трассировки стека

187
задан Yu Hao 15 March 2014 в 02:17
поделиться

12 ответов

Если Вы используете , Visual C++ делает следующее: Вы включаете intrin.h и вызываете следующие функции:

Для чисел на 16 битов:

unsigned short _byteswap_ushort(unsigned short value);

Для чисел на 32 бита:

unsigned long _byteswap_ulong(unsigned long value);

Для чисел на 64 бита:

unsigned __int64 _byteswap_uint64(unsigned __int64 value);

числа на 8 битов (символы) не должны быть преобразованы.

Также они только определяются для неподписанных значений, они работают на целые числа со знаком также.

Для плаваний и удваивается, это более трудно как с простыми целыми числами, как они могут или не могут быть в порядке байтов хост-машин. Можно получить плавания с прямым порядком байтов на машинах с обратным порядком байтов и наоборот.

Другие компиляторы имеют подобный intrinsics также.

В [1 117] GCC, например, можно непосредственно звонить:

int32_t __builtin_bswap32 (int32_t x)
int64_t __builtin_bswap64 (int64_t x)

(никакая потребность включать что-то). Afaik bits.h объявляет ту же функцию не gcc-центральным способом также.

16 битов подкачивают, это - просто бит - вращаются.

Вызов intrinsics вместо того, чтобы прокрутить Ваше собственное дает Вам лучшую производительность и плотность кода btw..

159
ответ дан Nils Pipenbrinck 23 November 2019 в 05:44
поделиться

Ищите разрядное смещение, поскольку это - в основном все, что необходимо сделать для свопинга от мало-> обратный порядок байтов. Тогда в зависимости от диаметра долота, Вы изменяетесь, как Вы делаете разрядное смещение.

-4
ответ дан Redbaron 23 November 2019 в 05:44
поделиться

Вот обобщенная версия, которую я придумал первое, что пришло на ум для свопинга значения на месте. Другие предложения были бы лучше, если производительность является проблемой.

 template<typename T>
    void ByteSwap(T * p)
    {
        for (int i = 0;  i < sizeof(T)/2;  ++i)
            std::swap(((char *)p)[i], ((char *)p)[sizeof(T)-1-i]);
    }

Правовая оговорка: я не попытался скомпилировать это или протестировать его все же.

2
ответ дан David Eisenstat 23 November 2019 в 05:44
поделиться

У меня есть этот код, которые позволяют мне преобразовывать из HOST_ENDIAN_ORDER (независимо от того, что это) к LITTLE_ENDIAN_ORDER или BIG_ENDIAN_ORDER. Я использую шаблон, поэтому если я попытаюсь преобразовать от HOST_ENDIAN_ORDER до LITTLE_ENDIAN_ORDER, и они, оказывается, то же для машины, для которой я компилирую, никакой код не будет сгенерирован.

Вот код с некоторыми комментариями:

// We define some constant for little, big and host endianess. Here I use 
// BOOST_LITTLE_ENDIAN/BOOST_BIG_ENDIAN to check the host indianess. If you
// don't want to use boost you will have to modify this part a bit.
enum EEndian
{
  LITTLE_ENDIAN_ORDER,
  BIG_ENDIAN_ORDER,
#if defined(BOOST_LITTLE_ENDIAN)
  HOST_ENDIAN_ORDER = LITTLE_ENDIAN_ORDER
#elif defined(BOOST_BIG_ENDIAN)
  HOST_ENDIAN_ORDER = BIG_ENDIAN_ORDER
#else
#error "Impossible de determiner l'indianness du systeme cible."
#endif
};

// this function swap the bytes of values given it's size as a template
// parameter (could sizeof be used?).
template <class T, unsigned int size>
inline T SwapBytes(T value)
{
  union
  {
     T value;
     char bytes[size];
  } in, out;

  in.value = value;

  for (unsigned int i = 0; i < size / 2; ++i)
  {
     out.bytes[i] = in.bytes[size - 1 - i];
     out.bytes[size - 1 - i] = in.bytes[i];
  }

  return out.value;
}

// Here is the function you will use. Again there is two compile-time assertion
// that use the boost librarie. You could probably comment them out, but if you
// do be cautious not to use this function for anything else than integers
// types. This function need to be calles like this :
//
//     int x = someValue;
//     int i = EndianSwapBytes<HOST_ENDIAN_ORDER, BIG_ENDIAN_ORDER>(x);
//
template<EEndian from, EEndian to, class T>
inline T EndianSwapBytes(T value)
{
  // A : La donnée à swapper à une taille de 2, 4 ou 8 octets
  BOOST_STATIC_ASSERT(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);

  // A : La donnée à swapper est d'un type arithmetic
  BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

  // Si from et to sont du même type on ne swap pas.
  if (from == to)
     return value;

  return SwapBytes<T, sizeof(T)>(value);
}
3
ответ дан Mathieu Pagé 23 November 2019 в 05:44
поделиться

В большинстве систем POSIX (через это не находится в стандарте POSIX) существует endian.h, который может использоваться для определения то, что использует кодирование системы. Оттуда это - что-то вроде этого:

unsigned int change_endian(unsinged int x)
{
    unsigned char *ptr = (unsigned char *)&x;
    return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
}

Это подкачивает порядок (от обратного порядка байтов до прямого порядка байтов):

, Если у Вас есть номер 0xDEADBEEF (в небольшой системе порядка байтов, сохраненной как 0xEFBEADDE), ptr [0], будет 0xEF, ptr[1] является 0xBE, и т.д.

, Но если Вы хотите использовать его для сетей, тогда htons, htonl, и htonll (и их инверсия ntohs, ntohl и ntohll) будет полезен преобразованию от порядка хоста до сетевого порядка.

6
ответ дан sifferman 23 November 2019 в 05:44
поделиться

Тем же путем Вы делаете в C:

short big = 0xdead;
short little = (((big & 0xff)<<8) | ((big & 0xff00)>>8));

Вы могли также объявить вектор неподписанных символов, memcpy входное значение в него, инвертировать байты в другой вектор и memcpy байты, но это будет слушаться величины дольше, чем битовое жонглирование, особенно с 64-разрядными значениями.

6
ответ дан Ben Straub 23 November 2019 в 05:44
поделиться

Если Вы делаете, это для передачи данных между различными платформами смотрит на ntoh и функции hton.

8
ответ дан Andrew 23 November 2019 в 05:44
поделиться

Мы сделали это с шаблонами. Вы могли так что-то вроде этого:

// Specialization for 2-byte types.
template<>
inline void endian_byte_swapper< 2 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    ushort* p_dest = reinterpret_cast< ushort* >(dest);
    ushort const* const p_src = reinterpret_cast< ushort const* >(src);
    *p_dest = (*p_src >> 8) | (*p_src << 8);
}

// Specialization for 4-byte types.
template<>
inline void endian_byte_swapper< 4 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    uint* p_dest = reinterpret_cast< uint* >(dest);
    uint const* const p_src = reinterpret_cast< uint const* >(src);
    *p_dest = (*p_src >> 24) | ((*p_src & 0x00ff0000) >> 8) | ((*p_src & 0x0000ff00) << 8) | (*p_src << 24);
}
12
ответ дан sifferman 23 November 2019 в 05:44
поделиться

Процедура движения от обратного порядка байтов до прямого порядка байтов совпадает с движением от прямого порядка байтов до обратного порядка байтов.

Вот некоторый пример кода:

void swapByteOrder(unsigned short& us)
{
    us = (us >> 8) |
         (us << 8);
}

void swapByteOrder(unsigned int& ui)
{
    ui = (ui >> 24) |
         ((ui<<8) & 0x00FF0000) |
         ((ui>>8) & 0x0000FF00) |
         (ui << 24);
}

void swapByteOrder(unsigned long long& ull)
{
    ull = (ull >> 56) |
          ((ull<<40) & 0x00FF000000000000) |
          ((ull<<24) & 0x0000FF0000000000) |
          ((ull<<8) & 0x000000FF00000000) |
          ((ull>>8) & 0x00000000FF000000) |
          ((ull>>24) & 0x0000000000FF0000) |
          ((ull>>40) & 0x000000000000FF00) |
          (ull << 56);
}
15
ответ дан Kevin 23 November 2019 в 05:44
поделиться

Существует инструкция по сборке под названием BSWAP, который сделает подкачку для Вас, чрезвычайно быстрый . Можно читать об этом здесь .

Visual Studio, или более точно библиотека времени выполнения Visual C++, имеет платформу intrinsics для этого, названного _byteswap_ushort(), _byteswap_ulong(), and _byteswap_int64(). Подобный должен существовать для других платформ, но я не знаю о том, чем их назвали бы.

15
ответ дан anon6439 23 November 2019 в 05:44
поделиться

При выполнении этого в целях совместимости сети/хоста, необходимо использовать:

ntohl() //Network to Host byte order (Long)
htonl() //Host to Network byte order (Long)

ntohs() //Network to Host byte order (Short)
htons() //Host to Network byte order (Short)

при выполнении этого по некоторой другой причине одно из byte_swap решений, представленных здесь, работало бы просто великолепно.

49
ответ дан Frosty 23 November 2019 в 05:44
поделиться

Я взял несколько предложений из этого сообщения и собрал их вместе, чтобы сформировать следующее:

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/endian.hpp>
#include <stdexcept>

enum endianness
{
    little_endian,
    big_endian,
    network_endian = big_endian,

    #if defined(BOOST_LITTLE_ENDIAN)
        host_endian = little_endian
    #elif defined(BOOST_BIG_ENDIAN)
        host_endian = big_endian
    #else
        #error "unable to determine system endianness"
    #endif
};

namespace detail {

template<typename T, size_t sz>
struct swap_bytes
{
    inline T operator()(T val)
    {
        throw std::out_of_range("data size");
    }
};

template<typename T>
struct swap_bytes<T, 1>
{
    inline T operator()(T val)
    {
        return val;
    }
};

template<typename T>
struct swap_bytes<T, 2>
{
    inline T operator()(T val)
    {
        return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
    }
};

template<typename T>
struct swap_bytes<T, 4>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff000000) >> 24) |
                (((val) & 0x00ff0000) >>  8) |
                (((val) & 0x0000ff00) <<  8) |
                (((val) & 0x000000ff) << 24));
    }
};

template<>
struct swap_bytes<float, 4>
{
    inline float operator()(float val)
    {
        uint32_t mem =swap_bytes<uint32_t, sizeof(uint32_t)>()(*(uint32_t*)&val);
        return *(float*)&mem;
    }
};

template<typename T>
struct swap_bytes<T, 8>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff00000000000000ull) >> 56) |
                (((val) & 0x00ff000000000000ull) >> 40) |
                (((val) & 0x0000ff0000000000ull) >> 24) |
                (((val) & 0x000000ff00000000ull) >> 8 ) |
                (((val) & 0x00000000ff000000ull) << 8 ) |
                (((val) & 0x0000000000ff0000ull) << 24) |
                (((val) & 0x000000000000ff00ull) << 40) |
                (((val) & 0x00000000000000ffull) << 56));
    }
};

template<>
struct swap_bytes<double, 8>
{
    inline double operator()(double val)
    {
        uint64_t mem =swap_bytes<uint64_t, sizeof(uint64_t)>()(*(uint64_t*)&val);
        return *(double*)&mem;
    }
};

template<endianness from, endianness to, class T>
struct do_byte_swap
{
    inline T operator()(T value)
    {
        return swap_bytes<T, sizeof(T)>()(value);
    }
};
// specialisations when attempting to swap to the same endianess
template<class T> struct do_byte_swap<little_endian, little_endian, T> { inline T operator()(T value) { return value; } };
template<class T> struct do_byte_swap<big_endian,    big_endian,    T> { inline T operator()(T value) { return value; } };

} // namespace detail

template<endianness from, endianness to, class T>
inline T byte_swap(T value)
{
    // ensure the data is only 1, 2, 4 or 8 bytes
    BOOST_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
    // ensure we're only swapping arithmetic types
    BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

    return detail::do_byte_swap<from, to, T>()(value);
}
25
ответ дан 23 November 2019 в 05:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: