符号付き整数と符号なし整数の違いは次のとおりです。
- 符号なしはより大きな正の値を保持でき、負の値は保持できません。
- 符号なしは先頭ビットを値の一部として使用しますが、符号付きバージョンは左端のビットを使用して数値が正か負かを識別します。
- 符号付き整数は、正と負の両方の数値を保持できます。
他に違いはありますか?
符号なしはより大きな正の値を保持でき、負の値は保持できません。
はい。
符号なしは先頭ビットを値の一部として使用しますが、符号付きバージョンは左端のビットを使用して数値が正か負かを識別します。
符号付き整数を表すさまざまな方法があります。視覚化する最も簡単な方法は、左端のビットをフラグ (符号と大きさ) として使用することですが、より一般的なのは2 の補数です。どちらも最新のマイクロプロセッサで使用されています — 浮動小数点は符号と絶対値を使用しますが、整数演算は 2 の補数を使用します。
符号付き整数は、正と負の両方の数値を保持できます。
はい。
x86 のハードウェア レベルでの相違点について説明します。これは、コンパイラを作成したり、アセンブリ言語を使用したりしない限り、ほとんど意味がありません。でも、知ってよかったです。
まず、x86 は符号付き数値の2 の補数表現をネイティブでサポートしています。他の表現を使用することもできますが、これにはより多くの命令が必要になり、通常はプロセッサ時間の無駄になります。
「ネイティブサポート」とはどういう意味ですか? 基本的には、符号なしの数値に使用する一連の命令と、符号付きの数値に使用する別のセットがあることを意味します。符号なしの数値は、符号付きの数値と同じレジスタに格納できます。実際、プロセッサを気にすることなく、符号付きと符号なしの命令を混在させることができます。数値が署名されているかどうかを追跡し、適切な命令を使用するのは、コンパイラ (またはアセンブリ プログラマ) 次第です。
まず、2 の補数には、加算と減算が符号なしの数値とまったく同じであるという性質があります。数値が正か負かは関係ありません。(ですから、心配することなく、番号を先に進めてADD
ください。)SUB
比較すると、違いが現れ始めます。x86 にはそれらを区別する簡単な方法があります。上/下は符号なしの比較を示し、より大きい/より小さいは符号付きの比較を示します。(たとえばJAE
、「以上または等しい場合にジャンプ」を意味し、署名されていません。)
符号付き整数と符号なし整数を処理するための乗算と除算の命令も 2 セットあります。
最後に、たとえばオーバーフローをチェックしたい場合は、符号付きの数値と符号なしの数値に対して異なる方法で行います。
彼は、署名されたものと署名されていないものについてのみ尋ねました。なぜ人々がこれに余分なものを追加しているのかわかりません。答えを教えてください。
符号なし: 0 から 255 までの負でない値のみで構成されます。
署名済み: 負の値と正の値の両方で構成されていますが、次のような異なる形式になっています。
そして、この説明は8ビットの数体系についてです。
クラスで学んだことによると、符号付き整数は正数と負数の両方を表すことができますが、符号なし整数は負でないだけです。
たとえば、8 ビットの数値を見ると、次のようになります。
符号0
なし値255
符号付きの値の範囲は-128
~127
完全を期すためのいくつかのポイント:
この答えは、整数表現のみを議論しています。浮動小数点には他の答えがあるかもしれません。
負の数の表現はさまざまです。今日使用されている最も一般的な (圧倒的に - 今日ではほぼ普遍的です) は、2 の補数です。他の表現には、1 の補数(非常にまれ) と符号付きマグニチュード(非常にまれ - おそらく博物館の作品でのみ使用される) が含まれます。これは単に上位ビットを符号インジケータとして使用し、残りのビットは数値の絶対値を表します。
2 の補数を使用すると、変数は、正の数よりも大きい範囲の負の数を (1 だけ) 表すことができます。これは、ゼロが「正の」数に含まれているため (符号ビットがゼロに設定されていないため)、負の数には含まれていないためです。これは、最小の負の数の絶対値を表すことができないことを意味します。
1 の補数または符号付きマグニチュードを使用する場合、0 を正数または負数として表すことができます (これは、これらの表現が通常使用されないいくつかの理由の 1 つです)。
ポイント2以外はすべて正しいです。signed int にはさまざまな表記法があり、最初のものを使用する実装もあれば、最後のものを使用する実装もあれば、まったく異なるものを使用する実装もあります。それはすべて、使用しているプラットフォームによって異なります。
もう1つの違いは、異なるサイズの整数間で変換する場合です。
たとえば、符号なしの値を使用して、バイトストリーム(簡単にするために16ビットなど)から整数を抽出する場合は、次のように実行できます。
i = ((int) b[j]) << 8 | b[j+1]
(おそらく2番目のバイトをキャストする必要がありますが、コンパイラーが正しいことを行うと思います)
符号付きの値を使用すると、符号拡張について心配し、次のことを行う必要があります。
i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
他の人が言ったことに加えて、C では、符号なし整数をオーバーフローさせることはできません。動作はモジュラス演算であると定義されています。符号付き整数をオーバーフローさせることができ、理論的には (現在の主流システムでは実際にはそうではありませんが)、オーバーフローによってエラーが発生する可能性があります (おそらくゼロによる除算のエラーに似ています)。
C の符号付き整数は数値を表します。a
とb
が符号付き整数型の変数である場合、標準では、コンパイラがそれぞれの値の算術和以外に式をa+=b
格納することを要求することはありません。a
確かに、算術合計が に収まらない場合a
、プロセッサはそれをそこに置くことができない可能性がありますが、標準では、コンパイラが値を切り捨てたりラップしたり、値がそれらのタイプの制限。標準では必須ではありませんが、C 実装では、符号付きの値で算術オーバーフローをトラップすることが許可されていることに注意してください。
C の符号なし整数は、より大きな型への変換または操作を伴うシナリオを除き、2 の累乗を法として合同である整数の抽象代数環として動作します。任意のサイズの整数を32 ビットの符号なし型に変換すると、その整数 mod 4,294,967,296 に一致するものに対応するメンバーが生成されます。2 から 3 を引くと 4,294,967,295 が得られる理由は、3 に合同なものを 4,294,967,295 に合同なものに足すと、2 に合同なものが得られるからです。
抽象代数環型は、あると便利なことがよくあります。残念ながら、C は、型がリングとして動作するかどうかの決定要因として符号を使用します。さらに悪いことに、符号なしの値は、より大きな型に変換されるときにリングメンバーではなく数値として扱われ、数値よりも小さい符号なしの値int
は、演算が実行されるときに数値に変換されます。v
がuint32_t
に等しい場合、4,294,967,294
をv*=v;
作成する必要がありv=4
ます。残念ながら、int
が 64 ビットの場合、何v*=v;
ができるかわかりません。
標準をそのまま考えると、代数環に関連する動作が必要な状況では符号なし型を使用し、数値を表現したい場合は符号付き型を使用することをお勧めします。C がそのように区別をつけたのは残念ですが、それらはそのままです。
一般的に言えば、それは正しいです。違いを探している理由についてこれ以上何も知らなければ、署名付きと未署名の間の他の差別化要因は考えられません。
(2 番目の質問への回答) (2 の補数ではなく) 符号ビットのみを使用すると、-0 になる可能性があります。あまりきれいではありません。
符号なし整数は、符号付き整数よりも特定のトラップに陥る可能性がはるかに高くなります。トラップは、上記の 1 と 3 は正しいものの、両方のタイプの整数に「保持」できる範囲外の値を割り当てることができ、サイレントに変換されるという事実から発生します。
unsigned int ui = -1;
signed int si = -1;
if (ui < 0) {
printf("unsigned < 0\n");
}
if (si < 0) {
printf("signed < 0\n");
}
if (ui == si) {
printf("%d == %d\n", ui, si);
printf("%ud == %ud\n", ui, si);
}
これを実行すると、両方の値が -1 に割り当てられ、異なる方法で宣言されていても、次の出力が得られます。
signed < 0
-1 == -1
4294967295d == 4294967295d
C で符号付きの値と符号なしの値の間で保証されている唯一の違いは、符号付きの値は負、0、または正のいずれかであり、符号なしは 0 または正の値のみであるということです。問題は、C が型の形式を定義していないことです (そのため、整数が 2 の補数であることを知りません)。厳密に言えば、あなたが言及した最初の 2 点は正しくありません。