原生Endians和自动转换

时间:2010-03-27 05:42:33

标签: c++ c endianness

所以以下将大端转换为小端

uint32_t ntoh32(uint32_t v)
{
    return (v << 24)
        | ((v & 0x0000ff00) << 8)
        | ((v & 0x00ff0000) >> 8)
        | (v >> 24);
}

的工作原理。喜欢魅力。

我从大端文件中读取4个字节到char v[4]并将其作为

传递给上面的函数
 ntoh32 (* reinterpret_cast<uint32_t *> (v))

不起作用 - 因为我的编译器(VS 2005)在我进行投射时会自动将大端字符[4]转换为小端uint32_t。

AFAIK,这种自动转换不可移植,所以我使用

uint32_t ntoh_4b(char v[])
{
    uint32_t a = 0;
    a |= (unsigned char)v[0];
    a <<= 8;
    a |= (unsigned char)v[1];
    a <<= 8;
    a |= (unsigned char)v[2];
    a <<= 8;
    a |= (unsigned char)v[3];
    return a;
}

是的(unsigned char)是必要的。 是的,这是狗慢。

必须有更好的方法。有谁?

3 个答案:

答案 0 :(得分:2)

更好的方法,恕我直言,正在使用htonlntohl函数。如果你想要真正便携,你不能想到“转换为小端”。相反,你应该考虑“转换为主机端”。这就是ntohl的用途,如果您的输入肯定是一个大端(这就是网络标准)。

现在,如果你单独读取你的字节,你可以把它们读作无符号长(在二进制模式下) - 这应该给你一个大端长,然后你可以将它转换成你需要的任何东西 - 如果你需要的话主持人,然后是ntohl

答案 1 :(得分:0)

狗慢了?你真的测量过了吗?您可以使用ntoh32的样式重写它,并显着减少操作次数:

uint32_t ntoh_4b(char v[])
{
    return ( (uint32_t)(unsigned char)v[0] << 24 )
         | ( (uint32_t)(unsigned char)v[1] << 16 )
         | ( (uint32_t)(unsigned char)v[2] <<  8 )
         | ( (uint32_t)(unsigned char)v[3]       );
}

答案 2 :(得分:0)

(将此作为保留缩进的单独答案)

试验台......

    union {
        char a[4];
        uint32_t i;
    } t;
    t.i = 0xaabbccdd;

    uint32_t v;
    for (uint32_t i = 0; i < -1; ++i)
    {
        //v = ntohl (t.i); (1)
        //v = ntoh32 (t.i); (2)
        //v = ntoh_4b (t.a);  (3)
    }

反汇编ntoh32 ......

movl    %edi, -4(%rbp)
movl    -4(%rbp), %eax
movl    %eax, %edx
sall    $24, %edx
movl    -4(%rbp), %eax
andl    $65280, %eax
sall    $8, %eax
orl %eax, %edx
movl    -4(%rbp), %eax
andl    $16711680, %eax
shrl    $8, %eax
orl %eax, %edx
movl    -4(%rbp), %eax
shrl    $24, %eax
orl %edx, %eax
leave

反汇编ntoh_4b ......

movq    %rdi, -8(%rbp)
movq    -8(%rbp), %rax
movzbl  (%rax), %eax
movzbl  %al, %eax
movl    %eax, %edx
sall    $24, %edx
movq    -8(%rbp), %rax
addq    $1, %rax
movzbl  (%rax), %eax
movzbl  %al, %eax
sall    $16, %eax
orl %eax, %edx
movq    -8(%rbp), %rax
addq    $2, %rax
movzbl  (%rax), %eax
movzbl  %al, %eax
sall    $8, %eax
orl %eax, %edx
movq    -8(%rbp), %rax
addq    $3, %rax
movzbl  (%rax), %eax
movzbl  %al, %eax
orl %edx, %eax
leave

最后,结果。我已经为C库ntohl提供了时间来提供比较基准

//v = ntohl (t.i); (1)
real    0m35.030s
user    0m34.739s
sys 0m0.245s   

//v = ntoh32 (t.i); (2)
real    0m36.272s
user    0m36.070s
sys 0m0.115s

//v = ntoh_4b (t.a);  (3)
real    0m40.162s
user    0m40.013s
sys 0m0.097s