2016-04-14 8 views
1

ポータブルな方法で整数をリトルエンディアンに/からリトルエンディアンに変換するにはどうすればよいのでしょうか。ポータブルな方法で整数からリトルエンディアンに変換する方法

これにはライブラリがありますか?

htonl and ntohlを使用して、ビッグエンディアンを(リミテッドから)リトルエンディアンに変換できますが、効率的ではありません。

+0

何を達成しようとしていますか?さまざまなサイズの整数へのポインターのファンキーなキャストや逆参照を行わない限り、エンディアンを心配する必要はありません。バイトスワップの代替方法については、["htonl()vs __builtin_bswap32()"](http://stackoverflow.com/questions/21527957/htonl-vs-builtin-bswap32)を参照してください。 – Jens

+2

もしあなたがエンディアンを手がかりにしなければならないのであれば、あなたはすでに "ポータブルではない"という領域を踏みとどまっています。したがって、コードの残りの部分が適切な抽象で動作するようにこれを分離し、***小さな***プラットフォーム固有の実装を特定のプラットフォーム用に実装します。 –

答えて

1

移植可能な方法は、ビットシフトとマスクを適切なサイズの文字列に使用することです。あなたがエンディアンに気を付ける必要があるのは、システム間でバイトを転送するときだけです。

不要な変換(リトルエンディアンアーキテクチャのリトルエンディアンに変換するなど)を避けたい場合は、コンパイル時に完全に移植可能な方法はありません。しかし、実行時に、変換関数のセットを動的に選択することができます。

これには、コードをインライン化できないという欠点があります。変換をポータブルな方法で記述し、テンプレートやインライン展開を使用する方が効率的かもしれません。準ポータブルのコンパイル時のチェックと組み合わせると、おなじみのものとほぼ同じです。

さらに読む:Detecting Endiannessコンパイル時。

+0

そのリンクのソリューションは実際には動作しません/移植性がありません。明示的キャストかユニオンかにかかわらず、constexprコンテキストのバイト列に整数をキャストすることは不正です。 –

1

これは大きな質問です。 constexpr式を使用してコンパイル時にエンディアンを判別する方法があるかどうかを確認するメッセージが表示されました。

プリプロセッサトリックがなければ、constexprコンテキストで評価するときに、整数をバイトのシーケンスに変換する方法がないため(キャストまたはユニオンを使用して)、プリプロセッサのトリックがないことが判明しました。

しかしそれはgccのでは、簡単な実行時のチェックは-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