memset()
これは と の両方に適用されますmemcpy()
。
- 少ないコード:既に述べたように、コードの行数が少なくて済みます。
- より読みやすい:通常、短いほど読みやすくなります。(
memset()
そのループよりも読みやすいです)
- より高速になる可能性があります。より積極的なコンパイラの最適化が可能になる場合があります。(だから早いかも)
- ミスアライメント:場合によっては、ミスアライメント アクセスをサポートしていないプロセッサでミスアライメント データを処理している
memset()
場合memcpy()
に、これが唯一のクリーンなソリューションである可能性があります。
3番目のポイントを拡張すると、memset()
SIMDなどを使用してコンパイラーによって大幅に最適化できます。代わりにループを記述する場合、コンパイラは、最適化を試みる前に、最初にループの動作を「把握」する必要があります。
ここでの基本的な考え方はmemset()
、同様のライブラリ関数が、ある意味でコンパイラに意図を「伝える」ということです。
コメントで @Oli が述べたように、いくつかの欠点があります。ここでそれらを拡張します。
memset()
それが実際にあなたが望むことをすることを確認する必要があります。標準は、さまざまなデータ型のゼロがメモリ内で必ずしもゼロであるとは言っていません。
- ゼロ以外のデータの場合、
memset()
内容は 1 バイトのみに制限されます。したがって、s のmemset()
配列をint
ゼロ以外 (0x01010101
または何か...) に設定する場合は使用できません。
- まれではありますが、独自のループでコンパイラのパフォーマンスを実際に上回る可能性があるいくつかのまれなケースがあります。
※私の経験から一例を挙げます。
memset()
とmemcpy()
は通常、コンパイラによる特別な処理を伴うコンパイラ組み込み関数ですが、依然として一般的な関数です。彼らは、データの配置を含むデータ型について何も言いません。
そのため、(まれではありますが) いくつかのケースでは、コンパイラはメモリ領域のアライメントを判断できず、ミスアライメントを処理するために追加のコードを生成する必要があります。一方、あなたがプログラマーである場合、アライメントが 100% 確実であれば、ループを使用する方が実際には高速になる可能性があります。
一般的な例は、SSE/AVX 組み込み関数を使用する場合です。(16/32 バイトでアラインされたfloat
s の配列をコピーするなど) コンパイラが 16/32 バイト アラインメントを判断できない場合、アラインされていないロード/ストアおよび/または処理コードを使用する必要があります。SSE/AVX に合わせたロード/ストア組み込み関数を使用して単純にループを作成する場合は、おそらくより適切に実行できます。
float *ptrA = ... // some unknown source, guaranteed to be 32-byte aligned
float *ptrB = ... // some unknown source, guaranteed to be 32-byte aligned
int length = ... // some unknown source, guaranteed to be multiple of 8
// memcopy() - Compiler can't read comments. It doesn't know the data is 32-byte
// aligned. So it may generate unnecessary misalignment handling code.
memcpy(ptrA, ptrB, length * sizeof(float));
// This loop could potentially be faster because it "uses" the fact that
// the pointers are aligned. The compiler can also further optimize this.
for (int c = 0; c < length; c += 8){
_mm256_store_ps(ptrA + c, _mm256_load_ps(ptrB + c));
}