【问题标题】:Swapping endians when using reinterpret cast使用重新解释转换时交换字节序
【发布时间】:2018-06-21 22:24:09
【问题描述】:

通过网络发送数据时,可以通过以下几种方式实现字节数据的转换:

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 时如何交换字节序?

【问题讨论】:

  • inBytes 是什么类型?请minimal reproducible example
  • *reinterpret_cast&lt;int32_t*&gt;(*inBytes); 应该是 *reinterpret_cast&lt;int32_t*&gt;(&amp;inBytes); ?
  • @tobi303 是的,抱歉。我试图缩短我的代码,这就是 & 迷路的地方。 inBytes 是一个无符号字符数组。
  • 使用std::memcpy(除非编译器没有优化掉它)和系统提供的函数(例如ntohl)来确保正确的字节序。
  • @PasserBy :这个。我真的,真的,真的希望更多的程序员这样做。

标签: c++ endianness reinterpret-cast


【解决方案1】:

你不能。重新解释强制转换只会改变编译器使用的类型,它不会触及数据。

正如How do I convert between big-endian and little-endian values in C++? 中所建议的那样 使用

int32_t __builtin_bswap32 (int32_t x)

【讨论】:

    【解决方案2】:

    您使用 reinterpret 和访问非活动的 union 成员都违反了标准。这么说的规则称为严格别名。

    因此,在您的选择中,变速是唯一符合标准的选择。

    另一个选项——memcpy 直接进入目标类型——也符合标准。

    您可以通过 memcpy 合法地对堆栈数组进行就地操作,在 tyoe 中放置新的,然后将 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 的方法在严格阅读标准时不再合法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 2014-11-29
      • 1970-01-01
      相关资源
      最近更新 更多