2011-07-28 12 views
6

バイト配列からint16(short)値を取得する最も効率的な方法は次のとおりですか?C++のバイト配列to

inline __int16* ReadINT16(unsigned char* ByteArray,__int32 Offset){ 
    return (__int16*)&ByteArray[Offset]; 
}; 

バイト配列にマシンと同じエンディアン形式のバイトのダンプが含まれている場合、このコードが呼び出されています。代替案は大歓迎です。

+1

「int」型は一般に、より良いメモリアクセスのためにマシンアーキテクチャと整列します。 'ByteArray [Offset]'が適切な整列を尊重していない( 'Offset'が奇数であるとすると)' __int16'を取得することは良い考えではないかもしれません。しかし、私たちはいくつかのより良い答えを待つことができます。 – iammilind

+0

アラインメントについて言及する人にとって、バイト配列はファイル形式であるため、1バイトを含むことがあります。オフセットは奇数になる可能性があります。これは問題ですか? – user826228

+0

@ user826228:はい、あなたのコードを移植したい場合は、潜在的な問題です。それがx86だけで実行されることがわかっていて、パフォーマンスが重要ではないなら、それを取り除くことができます。しかし、私はそれに反対します。 –

答えて

7

「効率的」という意味にもよりますが、アーキテクチャによっては、Offsetが奇数の場合にはこの方法は失敗します。結果の16ビットintは整列しないため、後で試してみると例外が発生しますそれにアクセスする。 Offsetが偶数であることが保証できる場合にのみ、この方法を使用してください。

inline int16_t ReadINT16(uint8_t *ByteArray, int32_t Offset){ 
    assert((Offset & 1) == 0); // Offset must be multiple of 2 
    return *(int16_t*)&ByteArray[Offset]; 
}; 

も注意してください、私はポインタを返すので、それは、直接16ビットの値を返すように、わずかにこれを変更し、その後、それが最も可能性が高い以下「効率的」だけで16ビットを返すより意志参照解除したこと直接価値。私は整数の標準Posix型にも切り替えました - 同じことをお勧めします。

+1

+1のために、誰もそれを拾うとは思わなかった。ほとんどのアーキテクチャーはこれをサポートしていますが、アライメントされたアクセスよりも遅いです。 –

+0

ByteArrayが偶数アドレスで開始しない場合はどうなりますか? – selbie

+0

@selbie:ByteArrayが静的に宣言されているか、 'new'または' malloc'で割り当てられている限り、これは可能ではありません。あなたが絶対に確実であることを望むならば、単に 'Offset'をテストするのではなく、'&ByteArray [Offset] 'のアライメントをテストすることができます。 –

0

私はこれに問題はない、それはまさに私がやっていることです。バイト配列が安全にアクセスでき、オフセットが正しいことを確認している限り(shortsは2バイトなので、奇数オフセットなどができないことを確認することができます)

-2

はい、それは効率的な方法ですが、IMHOはマクロを使う方が良いでしょう。あなたは、厳密なエイリアシング規則の下で許可されていない二つの異なるタイプを使用してストレージにアクセスしているので、残念ながら、これは、C++でbehavourを未定義た

+2

-1マクロを推薦するためには - これには正当な理由はなく、マクロにはインライン関数に比べて多くの欠点があります。 –

+1

私はあなたに同意しません。そのような小さな機能のために、マクロはより効率的です。この場合、マクロを使用すると、生成されたコードのパフォーマンスが向上し、インライン関数とは異なり、コンパイラがより効率的なコードを生成するのに役立ちます。 –

+2

私はあなたが実験を試みることをお勧めします - インライン関数を使って単純なマクロとその等価物を作成し、asm(例えばgcc -S)にコンパイルして出力を比較してください。貧しいコンパイラ。 –

0
inline __int16* ReadINT16(unsigned char* ByteArray,__int32 Offset) 
{  
    return (__int16*)&ByteArray[Offset]; 
}; 

char*を使用してタイプのストレージにアクセスすることはできますが、その逆はできません。

私は尋ねましたが、実際にmemcpyを使ってバイトをintにコピーしてから使用するのが唯一の安全な方法です。 (おそらくあなたが望む同じコードに最適化されるので、は恐らくと思われます)。

あなたのコードはおそらく動作しますが、ほとんどの人はこれをやっているようです...しかし、ポイントは、あなたがコンパイルベンダーに泣くことはできません。希望。

4

は、私は誰安全アライメントと全体のすべてのアーキテクチャ正しい両方で解決のために、まだこのことを示唆していない驚いています。 (まあ、8ビットから1バイトの任意のアーキテクチャ)。

inline int16_t ReadINT16(uint8_t *ByteArray, int32_t Offset) 
{ 
    int16_t result; 
    memcpy(&result, ByteArray+Offset, sizeof(int16_t)); 
    return result; 
}; 

そして私はmemcpyのオーバーヘッドを回避することができたとします

inline int16_t ReadINT16(uint8_t *ByteArray, int32_t Offset) 
{ 
    int16_t result; 
    uint8_t* ptr1=(uint8_t*)&result; 
    uint8_t* ptr2 = ptr1+1; 
    *ptr1 = *ByteArray; 
    *ptr2 = *(ByteArray+1); 
    return result; 
}; 

私はアライメントの問題は、x86上の例外を発生させないと考えています。そして、私が思い出したように、Windows(Dec Alphaなどで動作していたとき)は、整列例外をトラップし、それを修正します(適度なパフォーマンスで)。 SunOSのSparcが整列問題を抱えているときにクラッシュするという難しい方法を学ぶことを覚えています。

+0

私はデータをコピーするオーバーヘッドを避けようとしていました。小さなオーバーヘッドだとは思いますが、冗長なデータを使うのは悪い習慣だと思います。 – user826228