質問: 0; ``` よりも ``` hogeBit ^= hogeBit; ``` のほうがbitの0化のメモリの負担が少ないと述べていると認識しています。 ここでいう「多くのアーキテクチャ」というのがいつまでの時代のものを指すのかいまいち把握できてはいませんが、これは現在でも有効な手法なのでしょうか。 「有効」というのは「差が多かれ少なかれ負担が少ない」という解釈でお願いいたします。 よろしくお願いいたします。
回答: レジスタのゼロクリアとメモリのゼロクリアとでは状況が全く異なります。 x86プロセッサで説明すると、`XOR`命令は次の3種類です(他にもありますが...)。 * `REG ^= REG`(レジスタのゼロクリア) * `REG ^= MEM` * `MEM ^= REG` つまり`MEM ^= MEM`の命令が存在しないため、`XOR`を用いたメモリのゼロクリアとしては ``` REG = MEM MEM ^= REG ``` の2命令を必要とします。このことは1命令目のメモリ読み込みと`XOR`時のメモリ読み込みとで同じ値が読み込まれる保証がなくなり、ゼロクリアされない場合が生じ本末転倒です。 結局、**メモリのゼロクリアについてはゼロ値を書き込むほかありません**。 ゼロ値の生成方法については様々であります。もちろん`XOR`を使うことも可能ですが、そもそもその時点でゼロ値を保持しているレジスタがあればそれを流用することも可能ですし、レジスタに余裕がなければ即値で書き込むこともあるでしょう。 C言語やC++言語において`^=`がアトミック操作を保証しないのは上記の問題があるためです。 それとは別に通常はゼロクリアを目的とするプログラムではなく、ほかにメインの処理があることかと思います。ですので、ゼロクリアに重きを置いても意味がありません。 C++タグが付けられていますがアセンブラの話題に興味がある人が多いようなので... > > あと、直接は関係ありませんが、代入先の変数は16ビット(`short`)なのにレジスタは32ビット(`eax`)が使用されています。メモリに書き込む時点で16ビット修飾(`word ptr`)されています。なかなか興味深いですが、このやり方が最も効率的だと、コンパイラが判断したのでしょう。 > > > ``` 32 c0 ; XOR AL, AL 66 33 c0 ; XOR AX, AX 33 c0 ; XOR EAX, EAX ``` となっていて、16bitレジスタのクリアの場合、1byte長くなるため可能な限り32bit演算が選択されます。それとは別に後続命令がパーシャルレジスタストールを引き起こしかねないため、可能な限り8bitレジスタや16bitレジスタにはアクセスせず、32bit演算を行います。 なお、`XOR`命令はフラグレジスタを更新します。対して`MOV`命令は更新しません。ですので前後の命令によってはフラグレジスタを維持したままゼロクリアする手段として`MOV`が使われることもあり得ます。 それとは別に ``` 0f 57 c9 ; XORPS XMM1, XMM1 66 0f d6 4d f0 ; MOVQ MMWORD PTR _mem$[ebp], XMM1 ``` のようにSSE2を使用して16バイトをゼロクリアすることもできます。コンパイラーはこれを利用して連続する複数の変数を一気に初期化したりもできます。 こういったことがあるためC++言語においては初期化方法にこだわらずシンプルなコーディングを行い、コンパイラーに任せるのが一番です。