2016-04-14 31 views
1

我想知道以便攜方式將整數轉換成小尾數的推薦方式是什麼。如何將整數以便攜方式轉換爲小尾數

是否有任何圖書館?

我們可以使用htonl and ntohl,然後做一個大端到小端的轉換,但效率不高。

+0

你想達到什麼目的?除非你做了一些時髦的轉換和取消指向各種大小整數的指針,否則你不需要擔心endianess。另請參閱[「htonl()vs __builtin_bswap32()」](http://stackoverflow.com/questions/21527957/htonl-vs-builtin-bswap32)上的這個問題,它討論了字節交換數字的替代方法。 – Jens

+2

如果你不得不擺弄end,,你已經踏上了「不便攜」的境界。因此,以這樣一種方式來隔離它,其餘代碼可以使用適當的抽象,並且針對特定平臺實現*** ***平臺特定的實現。 –

回答

1

可移植的方式是使用位移和掩碼到適當大小的字符串中。注意我說的是字符串,因爲這實際上是唯一需要關注字節順序的時候 - 在系統之間傳輸字節。

如果你想避免不必要的轉換(例如在小端架構上轉換成小端),那麼編譯時就沒有完全可移植的方法。但是您可以在運行時檢查以動態選擇一組轉換函數。

這確實有代碼不能內聯的缺點。以便攜方式編寫轉換並使用模板或內聯可能會更有效。結合半可移植的編譯時檢查,這與你會得到的一樣好。

更多閱讀: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; 
} 

這裏編譯就當是彙編輸出。一個英特爾(小端)平臺:

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