どちらが速いのですか?割り当て対mempcy - この場合は速くなります
1.
char* _pos ..;
short value = ..;
*((short*)_pos = va;
2.
char* _pos ..;
short value = ..;
memcpy(_pos, &value, sizeof(short));
どちらが速いのですか?割り当て対mempcy - この場合は速くなります
1.
char* _pos ..;
short value = ..;
*((short*)_pos = va;
2.
char* _pos ..;
short value = ..;
memcpy(_pos, &value, sizeof(short));
すべての「より速い」と同様にあなたはあなた自身のためにそれをベンチマークするべきです。そしてそれが重要な場合は、理由を尋ね、あなたが欲しいものを選んでください。いずれの場合においても
あなたは、厳密なエイリアシングに違反しているので、あなたの最初の例では、技術的に未定義の動作です。だから、ベンチマークをせずに選択しなければならないのであれば、2つ目のベンチマークに行ってください。
高速です実際の質問は、おそらくpos
のアライメントに依存します答えること。それが適切に整列していれば、1はおそらくより速くなります。もしそうでなければ、コンパイラの最適化の仕方によっては2が速くなるかもしれません。ハードウェアがミスアライメントされたアクセスをサポートしていない場合、1がクラッシュする可能性があります。
これはすべての推測作業です。あなたは確かにそれを知るためにそれをベンチマークする必要があります。
非常に少なくとも、あなたは、コンパイル済みのアセンブリになります。この場合には(MSVCで)デフォルトの最適化と正確に同じアセンブリを示し
: *(short *)_pos = value;
mov WORD PTR [rcx], dx
対
: memcpy(_pos, &value, sizeof(short));
mov WORD PTR [rcx], dx
を。したがって、パフォーマンスは同じになると期待できます。
コンパイラはそれらを同じように両方を実装するかもしれません。
これが邪魔になると、割り当てが高速になります。
いずれの実用的な目的のためにも、それらはすぐに実行されるため、心配する必要はありません。
はまたpunning問題をあなたは(一部のプロセッサ上でクラッシュする可能性がある、_pos
2バイトに整列されない場合があります)アライメント問題sが持っている可能性があることに注意し、入力します(コンパイラが、何_pos
の点が変更されないためにことを仮定してもよいですあなたがshort *
を使って書いたからです)。
重要ですか?最初のケースではコンパイラーの洗練と最適化に依存していくらかのサイクルを節約することができます。しかし、読みやすさと保守性のヒットに価値があるのでしょうか?
時期尚早な最適化のために多くのバグが導入されています。まず、ボトルネックを特定し、この割り当てがボトルネックである場合は、それぞれのオプションをベンチマークします(すでに他の人がここで言及したアラインメントやその他の問題を処理します)。
質問は実装に依存します。実際には、sizeof(short)バイトをコピーするだけで何かをするために、もし遅くなるならmemcpyになるでしょう。かなり大きなデータセットの場合、高速化が進むと一般的にmemcpyになります。
指摘したように、#1は未定義の動作を呼び出します。
単純な割り当ては、読み書きが容易で、両方よりエラーが発生しにくいことがわかります。パフォーマンスが重要な領域であっても、最適化された不正なコードを修正するよりも、正しいコードを最適化する方が簡単であるという理由から、明快さと正確さが最優先です。これが本当にC++の質問であれば、そのようなコード(型システムをx-rayやドルにコピーするキャストやmemcpy)の必要性は非常にまれです。 -O1
以上の最適化レベルでgcc
で
は、次の2つの関数は、x86上でまったく同じマシンコードにコンパイルします。
void foo(char *_pos, short value)
{
memcpy(_pos, &value, sizeof(short));
}
void bar(char *_pos, short value)
{
*(short *)_pos = value;
}
あなたは、アライメントの問題がないことが確実な場合には、あなたは本当にこれがボトルネックの状況であることが分かり、最初にやります。
あなたはmemcpyのは、その後のような何かを呼び出す不満がある場合:あなたはその後、符号なしの値を使用することをやろうとしている場合が
*pos = static_cast<char>(value & 0xff);
*(pos+1) = static_cast<char>(value >> 8);
を。
上記のコードでは、リトルエンディアンも得られます。 (ビッグエンディアンが必要な場合は、割り当ての順序を逆にしてください)。データがある種のバイナリBLOBとして渡された場合、一貫したエンディアンが必要な場合があります。これは、作成しようとしているものです。
バイナリブロブを作成する場合は、Googleプロトコルバッファのようなものを使用することをおすすめします。バイナリのシリアライズを含むboost :: serializeもあります。あなたはエイリアシングルールを破ると組合を使用して関数を呼び出す避けることができ
:
union {
char* c;
short* s;
} _pos;
short value = ...
_pos->s = value;
1は2が遅くなり、より速く、危険である(それはそれは、コンパイラによって最適化することができたとしても関数を呼び出し)と危険です。 – vulkanino
あなたのプログラム割り当てのボトルネックは「短く」なっていますか? –
私は、メッセージデータのバイナリBLOBを作成していると思います。これは、メッセージをパックして解凍するために何度もやってしまうことでしょう。 – CashCow