Programming組込み/バックエンド開発者

Cにおけるビットシフト演算子(<<、>>)の動作メカニズムを説明してください。異なるタイプ(signed/unsigned)に対するルールは何ですか?不適切な使用がもたらす典型的なエラーにはどのようなものがありますか?また、それらを使用して効率的に解決できるタスクは何ですか?

Hintsage AIアシスタントで面接を突破

回答。

質問の歴史

ビット演算子は、データやハードウェアとの低レベルの操作を便利にするためにC言語に導入されました:レジスタの設定、マスキング、2の冪による乗算と除算。これらの動作ルールは、8ビットおよび16ビットプロセッサの時代に確立されました。

問題

signed型のシフトでしばしば間違いが発生します。結果は実装(算術シフトまたは論理シフト)によって異なり、タイプのサイズの境界を越えた場合にも問題が生じます。エラーはデータの破損、不正確な計算、未定義の動作を引き起こす可能性があります。

解決策

左シフト(<<): 値を2のk乗で乗算することと同等です(a << k)。常に右側にゼロを詰めます。

右シフト(>>): unsigned値の場合、左側にゼロを詰めます(論理シフト)。signedの場合は、符号ビットで埋める場合もあれば、ゼロで埋める場合もあります(動作はコンパイラによって異なります)。

例:

unsigned int x = 5; // 0000 0101 unsigned int y = x << 1; // 0000 1010 == 10 int z = -4; // 1111 1100(8ビットの場合) int w = z >> 1; // 1111 1110 (-2) または 0111 1110(実装に依存)

主な特徴:

  • 左右のシフトはunsigned型の数値に対して効果的です。
  • signed型の右シフトは異なる結果をもたらす可能性があるため、負の数の場合は注意が必要です。
  • 型のサイズ以上のビット数をシフトすると未定義の動作が発生します。

トリッキーな質問。

負の数を右にシフトするとどうなりますか?

結果は実装に依存します。最も一般的には符号を保持する算術シフトになりますが、標準ではこれを保証していません。

型のビット数より多くシフトした場合の結果はどうなりますか?

未定義の動作です。例えば、1 << 32は32ビット型の場合、何が返ってくるかわからず、プログラムがクラッシュする可能性があります。

浮動小数点数にビット演算子を使用できますか?

いいえ、標準のfloatやdouble型はビット演算をサポートしていません。整数型のみです。

典型的なエラーとアンチパターン

  • 満たし方を確認せずにsigned値を右にシフトする
  • "あまりにも多く"のビットをシフトすることによる型の境界を越える
  • float/doubleに適用する
  • ビットマスクにおいて明示的なunsignedなしで符号を使用する

実生活の例

ネガティブケース

プログラマがマスクを生成するためにintを32シフトしました—一部のプラットフォームでは0になり、他のプラットフォームでは認識できない値になりました。

利点:

  • 高速な乗算/除算

欠点:

  • 移植性のない不安定なコード

ポジティブケース

代わりにunsigned値を使用し、マクロでビット数をマスキングし、明確な文書とsizeofを使ったタイプの長さのチェックを行いました。

利点:

  • 振る舞いが明確で移植性がある

欠点:

  • 追加のチェックと例外処理のためのコードが必要です。