web-dev-qa-db-ja.com

符号付き整数のビット演算の結果は定義されていますか?

私は、>>符号付き整数は、実装に依存する場合があります(具体的には、左のオペランドが負の場合)。

他の人はどうですか:~>>&^|?オペランドが組み込み型の符号付き整数である場合(shortintlonglong long)、結果は、それらの型が符号なしであるかのように(ビット内容に関して)同じであることが保証されていますか?

44
updogliu

負のオペランドの場合、<<の動作は未定義であり、>>の結果は実装定義です(通常は「算術」右シフトとして)。 <<>>は、概念的にはビット単位の演算子ではありません。これらは、明確に定義されたオペランドに対して適切な2のべき乗による乗算または除算に相当する算術演算子です。

真のビット単位演算子^~|、および&については、オペランドの(昇格している可能性がある)型の値のビット表現を操作します。それらの結果は、符号付き表現(2の補数、1の補数、または符号の大きさ)の可能な選択肢ごとに明確に定義されていますが、後者の2つの場合、実装が「負のゼロ」を扱う場合、結果がトラップ表現になる可能性がありますトラップとしての表現。個人的には、ほとんど常にビット単位の演算子で符号なしの式を使用しているため、結果はrepresentationsではなくvaluesで100%明確に定義されています。

最後に、書かれたこの回答はCにのみ適用される可能性があることに注意してください.CとC++は非常に異なる言語であり、C++をよく知らない一方で、これらの領域の一部がCとは異なる可能性があることを理解しています...

42
R..
  • 負の値の左シフト<<の動作は未定義です。
  • 負の値の右シフト>>は、実装定義の結果をもたらします。
  • &|、および^演算子の結果は、値のビット単位表現で定義されます。 Cの負数の表現には、2の補数、1の補数、および符号の大きさの3つの可能性があります。実装で使用される方法は、これらの演算子が負の値で使用される場合の数値結果を決定します。

符号ビット1およびすべての値ビットがゼロの値(2の補数および符号の大きさ)、または符号ビットおよびすべての値ビット1の値(1の補数の場合)は、明示的にトラップ表現。この場合、そのような値を生成するこれらの演算子の引数を使用すると、動作は未定義になります。

10
caf

ビットの内容は同じですが、結果の値は実装に依存します。

ビット単位演算を使用する場合、値が符号付きまたは符号なしとして実際に表示されるべきではありません。それは異なるレベルで機能しているからです。

符号なしの型を使用すると、この問題のいくつかからあなたを救います。

4
Bo Persson

C89標準は、ビット位置に基づいて左シフト符号付き数値の動作を定義しました。符号付き型にも符号なし型にもパディングビットがない場合、符号なし型に必要な動作は、正符号付き型が符号なし型と同じ表現を共有するという要件と相まって、符号ビットが最上位値ビットのすぐ左側にあることを意味します。

これは、C89では、-1 << 1は、パディングビットのない2の補数の実装では-2であり、パディングビットのない1の補数の実装では-3です。パディングビットのない符号マグニチュード実装がある場合、-1 << 1はそれらに2になります。

C99規格は、負の値の左シフトを未定義の動作に変更しましたが、その理由についての根拠を示すものは何もありません(または、変更についてまったく言及していません)。 C89が必要とする動作は、一部の補数実装では理想的とは言えない可能性があるため、これらの実装がより良いものを選択できるようにすることは理にかなっています。標準の作成者が、品質の2の補数の実装がC89によって義務付けられているのと同じ動作を提供し続けることを意図していなかったことを示唆する証拠を見ていませんが、残念ながら実際にはそうは言いませんでした。

2
supercat