2016-04-14 9 views
1

Интересно, какой рекомендуемый способ конвертировать целое число в/из little-endian в переносном режиме.Как преобразовать целое число в little-endian в переносном режиме

Есть ли для этого библиотека?

Мы можем использовать htonl and ntohl, а затем сделать еще один большой треугольник для (из) мало-конечного преобразования, но он неэффективен.

+0

Что вы пытаетесь достичь? Если вы не делаете какое-то фанковое литье и разыменование указателей на целые числа разных размеров, вам не нужно беспокоиться о энтиансе. См. Также этот вопрос в разделе ["htonl() vs __builtin_bswap32()"] (http://stackoverflow.com/questions/21527957/htonl-vs-builtin-bswap32), в котором говорится об альтернативных способах байтов. – Jens

+2

Если вам нужно возиться с endianess, вы уже ступите в области «не переносимые». Таким образом, изолируйте это так, чтобы остальная часть вашего кода работала с подходящими абстракциями, а для небольших платформ реализованы небольшие мелкие *** реализационные реализации платформы. –

ответ

1

Портативный способ заключается в использовании бит-сдвигов и масок в строку соответствующего размера. Заметьте, я говорю строку, потому что это действительно единственный раз, когда вам нужно заниматься контентом - при передаче байтов между системами.

Если вы хотите избежать ненужных преобразований (например, преобразование в little-endian в архитектуре little-endian), нет полностью переносного способа сделать это во время компиляции. Но во время выполнения вы можете проверить динамический выбор набора функций преобразования.

Это имеет тот недостаток, когда код не может быть встроен. Возможно, было бы более эффективно писать конверсии переносимым способом и использовать шаблоны или встраивание. В сочетании с полупортативными проверками времени компиляции, это примерно так же хорошо, как вы получите.

Дополнительная информация: Detecting Endianness во время компиляции.

+0

решения в этой ссылке фактически не работают/не переносятся. Оказывается, незаконно вводить целое число в последовательность байтов в контексте constexpr, будь то явным литом или объединением. –

1

Это отличный вопрос. Это побудило меня посмотреть, есть ли какой-либо способ определить сущность во время компиляции, используя выражение constexpr.

Оказалось, что без препроцессорных трюков это невозможно, потому что нет возможности превратить целое число в последовательность байтов (через приведения или объединения) при оценке в контексте constexpr.

Однако оказывается, что в НКУ, простая проверка во время выполнения получает оптимизированную прочь при компиляции с -O2, так что это на самом деле оптимально эффективным:

#include <cstdint> 
#include <iostream> 

constexpr bool is_little_endian() 
{ 
    union endian_tester { 
     std::uint16_t n; 
     std::uint8_t p[4]; 
    }; 

    constexpr endian_tester sample = {0x0102}; 
    return sample.p[0] == 0x2; 
} 

template<class Int> 
Int to_little_endian(Int in) 
{ 
    if (is_little_endian()) { 
    return in; 
    } 
    else { 
    Int out = 0; 
    std::uint8_t* p = reinterpret_cast<std::uint8_t*>(std::addressof(out)); 
    for (std::size_t byte = 0 ; byte < sizeof(in) ; ++byte) 
    { 
     auto part = (in >> (byte * 8)) & 0xff; 
     *p++ = std::uint8_t(part); 
    } 

    return out; 
    } 
} 

int main() 
{ 
    auto x = to_little_endian(10); 
    std::cout << x << std::endl; 
} 

вот выход ассемблера при компиляции на платформа intel (little-endian):

main: 
     subq $8, %rsp 
# 
# here is the call to to_little_endian() 
# 

     movl $10, %esi 
# 
# that was it - it's been completely optimised away 
# 

     movl std::cout, %edi 
     call std::basic_ostream<char, std::char_traits<char> >::operator<<(int) 
     movq %rax, %rdi 
     call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&) 
     xorl %eax, %eax 
     addq $8, %rsp 
     ret