Herbert Schildt の著書「C The Complete Reference」には、「(符号付きの負の整数の場合、右シフトによって 1 が取り込まれ、符号ビットが保持される)」と書かれています。
符号ビットを保持するポイントは何ですか?
また、この本は、 2 の補数を使用せずに符号ビットを使用して負の数を表す場合について言及していると思います。しかし、その場合でも、推論は意味をなさないようです。
Herbert Schildt の著書「C The Complete Reference」には、「(符号付きの負の整数の場合、右シフトによって 1 が取り込まれ、符号ビットが保持される)」と書かれています。
符号ビットを保持するポイントは何ですか?
また、この本は、 2 の補数を使用せずに符号ビットを使用して負の数を表す場合について言及していると思います。しかし、その場合でも、推論は意味をなさないようです。
シルトの本は非常に貧弱であると広く認められています。
実際、Cでは、符号付きの負の数を右シフトしたときに 1 がシフトされることは保証されていません。負の値を右シフトした結果は実装定義です。
ただし、負の数の右シフトが 1 を最上位ビット位置にシフトするように定義されている場合、2 の補数表現では算術シフトとして動作します。N による右シフトの結果は除算と同じになります。 2 Nずつ、負の無限大に向かって丸めます。
この声明は、シルト氏による多くの声明と同様に、大雑把で不正確です。多くの人が彼の本を捨てることを勧めています。(他の場所の中でも、The Annotated Annotated C StandardおよびACCU Reviewsを参照してください — Schildt で著者検索を行います。Stack OverflowのDefinitive List of C Booksも参照してください)。
負の (必然的に符号付きの) 整数を右シフトすることで、上位ビットに 0 をシフトするか 1 をシフトするかは、実装で定義されます。基礎となる CPU (たとえば、ARM。このクラスも参照) には、多くの場合、2 つの異なる基礎となる命令 (ASR または算術右シフトと LSR または論理右シフト) があり、ASR は符号ビットを保持し、LSR は保持しません。コンパイラの作成者はどちらかを選択することができ、互換性、速度、または風変わりな理由で選択する場合があります。
ISO/IEC 9899:2011 §6.5.7 ビット単位のシフト演算子
¶5 の結果
E1 >> E2
はE1
右シフトされたE2
ビット位置です。符号なし型の場合E1
、または符号付き型E1
で負でない値の場合、結果の値は E1 / 2 E2の商の整数部分です。符号付きの型と負の値を持つ場合E1
、結果の値は実装定義です。
ポイントは、C >>
(右シフト) 演算子が a (signed) の符号を1int
に保持することです。
例えば:
int main() {
int a;
unsigned int b;
a = -8;
printf("%d (0x%X) >> 1 = %d (0x%X)\n", a, a, a>>1, a>>1);
b = 0xFFEEDDCC;
printf("%d (0x%X) >> 1 = %d (0x%X)\n", b, b, b>>1, b>>1);
return 0;
}
出力:
-8 (0xFFFFFFF8) >> 1 = -4 (0xFFFFFFFC) [sign preserved, LSB=1]
-1122868 (0xFFEEDDCC) >> 1 = 2146922214 (0x7FF76EE6) [MSB = 0]
符号が保持されない場合、結果はまったく意味をなしません。小さな負の数を取り、右に 1 つシフトする (2 で割る) と、代わりに大きな正の数になります。
1 - これは実装定義ですが、私の経験からすると、ほとんどのコンパイラは算術 (符号保存) シフト命令を選択します。
符号付きの負の整数の場合、右シフトによって 1 が取り込まれ、符号ビットが保持されます。
必ずしも。C 標準 C11 6.5.7 を参照してください。
E1 >> E2 の結果は、E1 を右シフトした E2 ビット位置です。E1 が unsigned 型の場合、または E1 が signed 型で負でない値の場合、結果の値は E1 / 2 E2の商の整数部分になります。E1 に符号付きの型と負の値がある場合、結果の値は実装定義です。
これは、コンパイラが文書化されている限り、コンパイラが好きなもの (0 または 1) を自由にシフトできることを意味します。