代码之家  ›  专栏  ›  技术社区  ›  hidayat

C++中的双位交换

  •  4
  • hidayat  · 技术社区  · 14 年前

    double val, tmp = 5.55;
    
    ((unsigned int *)&val)[0] = ntohl(((unsigned int *)&tmp)[1]);
    ((unsigned int *)&val)[1] = ntohl(((unsigned int *)&tmp)[0]);
    

    但是我得到一个警告:“取消引用类型punned指针将破坏严格的别名规则”,我不想关闭这个警告。

    另一种方法是:

    #define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) ) 
    
    val = (double)bswap_64(unsigned long long(tmp)); //or
    val = (double)ntohll(unsigned long long(tmp));
    

    但是a失去了小数。 有人知道不使用for循环交换double上的位的好方法吗?

    3 回复  |  直到 14 年前
        1
  •  9
  •   GManNickG    14 年前

    我可能会这样做:

    template <typename T>
    void swap_endian(T& pX)
    {
        // should static assert that T is a POD
    
        char& raw = reinterpret_cast<char&>(pX);
        std::reverse(&raw, &raw + sizeof(T));
    }
    

    复制版本,用于不想修改参数时:

    template <typename T>
    T swap_endian_copy(T pX)
    {
        swap_endian(pX);
        return pX;
    }
    
        3
  •  0
  •   Goz    14 年前

    你就不能交换一下吗?

    inline unsigned long long EndianChange( double d )
    {
        char ch[8];
        memcpy( ch, &d, 8 );  // Note this will be optimised out completely by pretty much every compiler.
        ch[0] ^= ch[7] ^= ch[0] ^= ch[7]; 
        ch[1] ^= ch[6] ^= ch[1] ^= ch[6];
        ch[2] ^= ch[5] ^= ch[2] ^= ch[5];
        ch[3] ^= ch[4] ^= ch[3] ^= ch[4];
    
        unsigned long long dRet;
        memcpy( &dRet, ch, 8 ); // Again this will get optimised out.
        return dRet;
    };
    

    编辑:正如所指出的那样,字节交换的双精度“可以”加载到寄存器中,这样将其从该寄存器中取出就意味着该值不再有效,所以将其存储在一个长的64位中以避免此问题。

    这就是字节交换的全部内容。我不知道你想做什么,但是我用过的每一个big-endian平台都使用与little-endian相同的编码,只是字节顺序颠倒了。上面的代码将为您反转字节顺序。几乎所有的编译器都只需进行字节交换,然后返回字节交换的变量并去掉memcpy。这是处理别名问题的好方法。