Родные Порядки и Авто Конверсия - PullRequest
2 голосов
/ 27 марта 2010

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

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 ]

2 голосов
/ 27 марта 2010

Лучший способ, IMHO, использовать функции htonl и ntohl.Если вы хотите быть действительно переносимым, вы не можете думать с точки зрения «преобразовать в little-endian».Скорее вы должны подумать о "преобразовать в хост endian".Это то, для чего нужен ntohl, если ваш входной код точно соответствует порядку байтов (именно таков сетевой стандарт).

Теперь, если вы читаете свои байты по отдельности, вы можете читать их как неподписанныеlong (в двоичном режиме) - это должно дать вам long-endian long, а затем вы можете преобразовать его во все, что вам нужно - если вам нужен endian хоста, то ntohl.

0 голосов
/ 29 марта 2010

(Публикация этого как отдельный ответ для сохранения отступа)

Испытательная установка ...

    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)
    }

разборка нто32 ...

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

И, наконец, результаты. Я включил время для ntohl библиотеки C, чтобы обеспечить базовый уровень для сравнения

//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
0 голосов
/ 27 марта 2010

Собака медленная? Вы действительно измерили это? Вы можете переписать его в стиле 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]       );
}
...