如何字节换一个双?

Dar*_*ell 6 c++ endianness visual-studio-2008

我正在尝试为在Win XP上运行的C++程序编写一个byteswap例程.我正在使用Visual Studio 2008编译.这就是我想出的:

int byteswap(int v) // This is good
{
    return _byteswap_ulong(v);
}

double byteswap(double v) // This doesn't work for some values
{
    union { // This trick is first used in Quake2 source I believe :D
        __int64 i;
        double  d;
    } conv;
    conv.d = v;
    conv.i = _byteswap_uint64(conv.i);
    return conv.d;
}
Run Code Online (Sandbox Code Playgroud)

还有一个测试功能:

void testit() {
    double  a, b, c;
    CString str;

    for (a = -100; a < 100; a += 0.01) {
        b = byteswap(a);
        c = byteswap(b);
        if (a != c) {
            str.Format("%15.15f %15.15f %15.15f", a, c, a - c);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

获取这些数字不匹配:

-76.789999999988126 -76.790000000017230 0.000000000029104  
-30.499999999987718 -30.499999999994994 0.000000000007276  
 41.790000000014508  41.790000000029060 -0.000000000014552  
 90.330000000023560  90.330000000052664 -0.000000000029104

这是在阅读之后:
如何在C++中的big-endian和little-endian值之间进行转换?
Little Endian - Big Endian问题
顺便说一下你不能在双重上使用<<和>>(除非我弄错了?)

Tho*_*mas 6

虽然double在主存储器中是64位,但在x86 CPU上,双精度寄存器是80位宽.因此,如果您的一个值全部存储在寄存器中,但另一个值通过主存储器往返并被截断为64位,这可以解释您所看到的小差异.

也许你可以通过获取地址(并打印它,以防止编译器优化它)来强制变量存在于主存储器中,但我不确定这是否可以保证工作.


Han*_*ant 5

    b = byteswap(a);
Run Code Online (Sandbox Code Playgroud)

这是个问题。交换字节后,该值不再是正确的双精度值。当 FPU 对值进行规范化时,将其存储回双精度值会导致微妙的问题。您必须将其存储回 __int64 (long long)。修改方法的返回类型。


Dar*_*ell 5

尝试 3

好的,发现有更好的方法。另一种方式是您必须担心打包/拆包的顺序。这样你就不会:

// int and float
static void swap4(void *v)
{
    char    in[4], out[4];
    memcpy(in, v, 4);
    out[0] = in[3];
    out[1] = in[2];
    out[2] = in[1];
    out[3] = in[0];
    memcpy(v, out, 4);
}

// double
static void swap8(void *v)
{
    char    in[8], out[8];
    memcpy(in, v, 8);
    out[0] = in[7];
    out[1] = in[6];
    out[2] = in[5];
    out[3] = in[4];
    out[4] = in[3];
    out[5] = in[2];
    out[6] = in[1];
    out[7] = in[0];
    memcpy(v, out, 8);
}

typedef struct
{
    int theint;
    float   thefloat;
    double  thedouble;
} mystruct;


static void swap_mystruct(void *buf)
{
    mystruct    *ps = (mystruct *) buf;
    swap4(&ps->theint);
    swap4(&ps->thefloat);
    swap8(&ps->thedouble);
}    
Run Code Online (Sandbox Code Playgroud)

发送:

    char    buf[sizeof (mystruct)];
    memcpy(buf, &s, sizeof (mystruct));
    swap_mystruct(buf);
Run Code Online (Sandbox Code Playgroud)

接收:

    mystruct    s;
    swap_mystruct(buf);
    memcpy(&s, buf, sizeof (mystruct));
Run Code Online (Sandbox Code Playgroud)