Замена байтов при использовании переинтерпретации

При отправке данных по сети преобразование байтовых данных может осуществляться несколькими способами:

12345  --> {0 0 48 57}

typedef unsigned char byte;

//1. Bit shift
int32_t shiftedInteger =  (int32_t) (inBytes[0] << 24 | inBytes[1] << 16  | 
inBytes[2] << 8 | inBytes[3]);

//2. Reinterpret cast
int32_t reinterpretedInteger = *reinterpret_cast<int32_t*>(&inBytes);

//3. Using unions
union{
    byte b[4];
    int32_t i;
}unionCast;

memcpy(unionCast.b,inBytes,4);
int_32t unionCasted = unctionCast.i;

Какой способ преобразования данных предпочтительнее (использование на Arduino, подобном микропроцессору)?

Метод union и reinterpretCast сталкивается с проблемами больших и маленьких байтов, но пригодится при работе с числами с плавающей запятой, поскольку простых битовых сдвигов будет недостаточно для обратного преобразования данных. Как поменять местами порядок байтов при использовании reinterpret_cast?


person Kilian    schedule 12.01.2018    source источник
comment
какой тип inBytes ? Пожалуйста, минимальный воспроизводимый пример   -  person 463035818_is_not_a_number    schedule 12.01.2018
comment
*reinterpret_cast<int32_t*>(*inBytes); должно быть *reinterpret_cast<int32_t*>(&inBytes); ?   -  person 463035818_is_not_a_number    schedule 12.01.2018
comment
@ tobi303 Да, извини. Я попытался сократить свой код, где & потерялся. inBytes — это неподписанный массив символов.   -  person Kilian    schedule 12.01.2018
comment
Используйте std::memcpy (если только компилятор не оптимизирует его) и предоставленную системой функцию (например, ntohl) для обеспечения правильного порядка следования байтов.   -  person Passer By    schedule 12.01.2018
comment
@PasserBy: это. Я очень, очень, очень хочу, чтобы больше программистов делали это.   -  person Daniel Kamil Kozar    schedule 13.01.2018


Ответы (2)


Использование вами переинтерпретации и доступ к неактивным членам союза нарушают стандарт. Правила, говорящие об этом, известны как строгие псевдонимы.

Таким образом, из ваших вариантов переключение передач является единственным стандартным.

Дополнительная опция — memcpy непосредственно в целевом типе — также соответствует стандарту.

Вы можете сделать это на месте с помощью memcpy в массив стека, поместив новый перед ним, а затем memcpy обратно. Оптимизатор устранит memcpys!

Вы даже можете сделать это:

template<class T> 
struct raw_bytes:
  std::array<char, sizeof(T)>
{
  static_assert(std::is_pod<T>::value, "pod only");
  static raw_bytes to_raw( T in ){
    raw_bytes r;
    std::memcpy( r.data(), std::addressof(in), sizeof(T) );
    return r;
  }
  // this object no longer valid after convert, but returned reference is until this object destroyed
  T& convert(){
    char tmp[sizeof(T)];
    memcpy(tmp, data(), sizeof(T));
    T* r= ::new( (void*)data() ) T;
    memcpy(r, tmp, sizeof(T));
    return *r;
  }
};

что может и не стоит.

Вы можете вставить raw_bytes в структуру и вставить в нее байты. Затем вы можете convert() этих байтов на месте преобразовать в T. Возвращаемая ссылка — единственный способ законного доступа к этим байтам; методы raw_bytes больше не являются законными при строгом чтении стандарта.

person Yakk - Adam Nevraumont    schedule 12.01.2018

Вы не можете. Приведение Reinterprert только изменяет тип, который использует компилятор, но не затрагивает данные.

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

int32_t __builtin_bswap32 (int32_t x)
person Sorin    schedule 12.01.2018