5

私は C の初心者です。私は最近、2's Complement負の数を表す他の方法と、それ2's complementが最も適切な理由について学びました。

私が聞きたいのは、例えば、

int a = -3;
unsigned int b = -3; //This is the interesting Part.

さて、int型の変換について

標準は次のように述べています。

6.3.1.3 符号付きおよび符号なし整数

整数型の値が _Bool 以外の別の整数型に変換される場合、その値が新しい型で表現できる場合、その値は変更されません。

それ以外の場合、新しい型が符号なしの場合、値が新しい型の範囲内になるまで、新しい型で表現できる最大値よりも 1 多い値を繰り返し加算または減算することによって、値が変換されます。

-3で表すことができないため、最初の段落は使用できませんunsigned int

したがって、段落 2 が有効になり、unsigned int の最大値を知る必要があります。limits.hでUINT_MAXとして見つけることができます。この場合の最大値は であるため、計算は次のとおりです。4294967295

-3 + UINT_MAX + 1 = -3 + 4294967295 + 1 = 4294967293  

現在4294967293、バイナリ11111111 11111111 11111111 11111101-32の補数形式は11111111 11111111 11111111 11111101本質的に同じビット表現であるため、符号なしintに割り当てようとしている負の整数に関係なく、常に同じになります.したがって、符号なし型は冗長ではありません.

これは標準によると未定義の動作であることはわかっていますprintf("%d" , b)が、合理的でより直感的な方法ではありません。負が として表されている場合、表現は同じ2's Complementであり、それが現在のものであり、使用される他の方法はまれであり、おそらく将来の開発ではありません.

したがって、 int と言う型が 1 つしかない場合、符号ビットint x = -1%dチェックし、符号ビットが である場合は負の数を出力1し、%u常にプレーン 2 進数 (ビット) をそのまま解釈します。を使用しているため、加算と減算は既に処理されてい2's complementます。ですから、これはより直感的で単純な方法ではありません。

4

4 に答える 4

3

私の答えはより抽象的です.Cでの私の意見では、メモリ内の整数の表現を気にするべきではありません. C はこれを抽象化します。これは非常に優れています。

unsigned非常に便利なように整数を宣言します。これは、値が決して負にならないことを前提としています。浮動小数点数ハンドルの実数と同様に、signed整数ハンドル...整数とunsigned整数ハンドルの自然数。

負の整数が未定義の動作につながるアルゴリズムを作成する場合。符号なし整数値が負にならないことを確認できます。たとえば、配列のインデックスを反復処理する場合。負のインデックスは、未定義の動作につながります。

もう 1 つのことは、パブリック API を作成するときです。関数の 1 つがサイズ、長さ、重み、または負の意味を持たないものを必要とする場合です。これは、ユーザーがこの値の目的を理解するのに役立ちます。


一方、 の算術演算がunsigned人々が最初に期待したように機能しないため、反対する人もいます。unsignedゼロに等しいときに anがデクリメントされると、非常に大きな値に渡されるためです。一部の人々は、彼が に等しいと予想してい-1ます。例えば:

// wrong
for (size_t i = n - 1; i >= 0; i--) {
  // important stuff
}

これにより、無限ループが生成されます。n がゼロの場合はさらに悪いことに、コンパイラはおそらくそれを検出しますが、常にではありません。

// wrong
size_t min = 0;
for (size_t i = n - 1; i >= min; i--) {
  // important stuff
}

符号なし整数でこれを行うには、ちょっとしたトリックが必要です。

size_t i = n;
while (i-- > 0) {
  // important stuff
}

私の意見でunsignedは、言語で整数を使用することは非常に重要であり、C はそれなしでは完全ではありません。

于 2016-12-31T13:44:04.593 に答える