これは、C と 2 進演算の両方がどのように機能するかです。
Shift を左0xff << 3
にすると、バイナリが得られます。00000000 11111111 << 3 = 00000111 11111000
を右にシフト0xff >> 3
すると、バイナリが得られます。00000000 11111111 >> 3 = 00000000 00011111
0xff
正の値を持つ (符号付き) int です255
。これは正であるため、シフトの結果は、C と C++ の両方で明確に定義された動作になります。算術シフトも、種類や定義が不十分な動作も行いません。
#include <stdio.h>
int main()
{
printf("%.4X %d\n", 0xff << 3, 0xff << 3);
printf("%.4X %d\n", 0xff >> 3, 0xff >> 3);
}
出力:
07F8 2040
001F 31
つまり、期待どおりに動作しないため、プログラムで奇妙なことをしているということです。char 変数または C++ 文字リテラルを使用している可能性があります。
出典: ISO 9899:2011 6.5.7.
質問の更新後に編集
int number = ~0;
2 の補数を仮定すると、-1 に相当する負の数が得られます。
number = number << 4;
負の数を左シフトしたため、未定義の動作が発生します。プログラムは未定義の動作を正しく実装します。これは、何かを実行するか、まったく実行しないためです。fffffff0 を出力するか、ピンクの象を出力するか、ハード ドライブをフォーマットする可能性があります。
number = number >> 4;
実装定義の動作を呼び出します。あなたの場合、コンパイラは符号ビットを保持します。これは算術シフトと呼ばれ、算術右シフトは、MSB がシフト前のビット値で満たされるように機能します。したがって、負の数を持っている場合、プログラムが「1 にシフト」していることを経験します。
実世界のすべてのケースの 99% では、符号付き数値にビット単位の演算子を使用しても意味がありません。したがって、常に符号なしの数値を使用していること、および C/C++ の危険な暗黙の変換規則のいずれによっても符号付き数値に変換されていないことを確認してください (危険な変換の詳細については、「整数昇格規則」および「通常の算術変換」を参照してください)。 "、SOに関する多くの良い情報)。
EDIT 2、C99標準の根拠文書V5.10からの情報:
6.5.7 ビットシフト演算子
K&R のシフト演算子の説明では、長いカウントでシフトすると、シフトされる前に左側のオペランドが長く拡張される必要があることが示唆されています。C89 委員会によって承認されたより直感的な方法は、シフト カウントの型が結果の型に関係しないというものです。
C89の静かな変化
long カウントでシフトしても、シフトされたオペランドが long に強制されなくなりました。C89 委員会は、K&R によって付与された実装の自由を確認し、符号付き右シフト操作を符号拡張する必要はありません。そのような要件は高速コードを遅くする可能性があり、符号拡張シフトの有用性はわずかであるためです。(負の 2 の補数の整数を算術的に右に 1 桁シフトすることは、2 で割ることと同じではありません!)