2011-02-03 3 views
4
template<int size> 
inline void* byteswap(void* __x); 

template<> 
inline void* byteswap<2>(void* __x) 
{ 
    return (*(uint16*)__x >> 8) | (*(uint16*)__x << 8); 
} 

template<> 
inline void* byteswap<4>(void* __x) 
{ 
    return (byteswap<4>(__x & 0xffff) << 16) | (bswap_16 (__x >> 16)); 
} 

template<typename T> 
inline T byteswap(T& swapIt) 
{ 
    return (T*)byteswap<sizeof(T)>(swapIt); 
}  

int main() { 
    uint32 i32 = 0x01020304; 
    uint16 i16 = 0x0102; 

    byteswap(i32); 
    byteswap(i16); 

    return 0; 
} 

上記は明らかにコンパイルされません。私は、関数のパラメータとしてvoid *が必要なように思えるので、私は混乱しています。バイトバッックではおかしくなります< 4>参照を使ってbyteswap <を呼び出す必要があります。templatizing byteswapping関数のヘルプは、パフォーマンスヒット?

これをきれいにするにはどうすればいいですか?ビット操作を直接行うようなパフォーマンスを実現するために(インライン展開やその他のトリックを使用して)可能ですか?

+1

2つの先頭のアンダースコアを使用しないでください、それらは予約されています! – Simone

+0

おい、フレッド、どこにいよう! – chriskirk

+0

Hah;私はこれが2日間で3回目であったことを認識していませんでした。あなたの質問の1つにコメントして答えに移しました。 :) –

答えて

4

これは私がそれをコーディングしたい方法です:他の言葉で

#include <iostream> 

typedef unsigned short uint16; 
typedef unsigned int uint32; 

template<typename T> T byteswap(T value); 

template<> 
uint16 byteswap<uint16>(uint16 value) 
{ 
    return (value >> 8)|(value << 8); 
} 

template<> 
uint32 byteswap<uint32>(uint32 value) 
{ 
    return uint32(byteswap<uint16>(value) << 16) | byteswap<uint16>(value >> 16); 
} 

int main() { 
    uint32 i32 = 0x11223344; 
    uint16 i16 = 0x2142; 

    std::cout << std::hex << byteswap(i32) << std::endl; // prints 44332211 
    std::cout << std::hex << byteswap(i16) << std::endl; // prints 4221 
} 

、あなたがやっていたように私は、テンプレートパラメータとしてサイズを使用していないだろう。

EDIT
申し訳ありませんが、私の最初のコードは単純に間違っWRT/UINT32スワッピングました。

0

私はそのようにそれを書き直します:

template < size_t size > 
inline void sized_byteswap(char* data); 

template <> 
inline void sized_byteswap<2>(char* data) 
{ 
    uint16_t* ptr = reinterpret_cast<uint16_t*>(data); 
    *ptr = (*ptr >> 8)|(*ptr << 8); 
} 

template <> 
inline void sized_byteswap<4>(char* data) 
{ 
    uint32_t* ptr = reinterpret_cast<uint32_t*>(data); 
    *ptr = (*ptr >> 24)|((*ptr & 0x00ff0000) >> 8)|((*ptr & 0x0000ff00) << 8)|(*ptr << 24); 
} 

template < typename T > 
T byteswap(T value) 
{ 
    sized_byteswap< sizeof(T) >(reinterpret_cast<char*>(&value)); 
    return value; 
} 

int main() 
{ 
    uint32 i32 = byteswap(uint32(0x01020304)); 
    uint16 i16 = byteswap(uint16(0x0102)); 

    return 0; 
} 
2

Borrowing from some code

template<int N> 
void byteswap_array(char (&bytes)[N]) { 
    // Optimize this with a platform-specific API as desired. 
    for (char *p = bytes, *end = bytes + N - 1; p < end; ++p, --end) { 
    char tmp = *p; 
    *p = *end; 
    *end = tmp; 
    } 
} 

template<typename T> 
T byteswap(T value) { 
    byteswap_array(*reinterpret_cast<char (*)[sizeof(value)]>(&value)); 
    return value; 
} 
+0

フレッドは、エレガントでフレキシブルですが、私は@ Simoneの解決策がより簡単であり、ループを設定するよりも少しパフォーマンスが良いと思います。どう思いますか?私は16ビットと32ビットのバイトワーピングルーチンしか必要としません。 – chriskirk

+1

@chriskirk:16ビットと32ビットのみが必要な場合は、リトルエンディアンマシンでhtonsとhtonlを使うか、ビッグエンディアンで使うためにその実装をコピーしてください。ループの反復は、コンパイル時の定数Nに依存するので一定です。最適化コンパイラがそれを展開することが期待されます。 [先験的な仮定](http://tinyurl.com/knuth-premature)に注意してください。最悪の場合、手動でループを展開するbyteswap_arrayの明示的なインスタンス化を提供できます。 –

+0

@chriskirk:16ビットと32ビットだけが必要な場合は、なぜこれをすべて気にして、過負荷を書くのではないのですか? – Puppy

関連する問題