符号付き整数と符号なし整数の違いは、次のとおりです。
他に違いはありますか?
X86上では、ハードウェアレベルで違いを調べます。コンパイラを書いたり、アセンブリ言語を使っているのでなければ、これはほとんど無関係です。しかし、知っておくといいですね。
まず、x86はnativeの符号付き数字の 2の補数表現 をサポートしています。他の表現を使用することもできますが、これはより多くの命令を必要とし、一般的にはプロセッサ時間の浪費になります。
「ネイティブサポート」とはどういう意味ですか?基本的に、符号なしの番号に使用する一連の手順と、符号付きの番号に使用する別の一連の手順があることを意味します。符号なし数値は符号付き数値と同じレジスタに格納できます。実際、プロセッサを気にせずに符号付き命令と符号なし命令を混在させることができます。番号が署名されているかどうかを追跡し、適切な命令を使用するのはコンパイラ(またはアセンブリプログラマ)次第です。
第一に、2の補数は、加減算が符号なしの数と全く同じであるという性質を持っています。数値が正でも負でも、違いはありません。 (それで、あなたはただ先に進み、あなたの数字をADD
とSUB
にして心配することなく)
比較すると、違いが現れ始めます。 x86はそれらを区別する簡単な方法を持っています:上/下は符号なしの比較を示し、大/小は符号付きの比較を示します。 (例:JAE
は「上記の値以上であればジャンプ」を意味し、符号なしです。)
符号付き整数と符号なし整数を処理するための乗算と除算の命令も2セットあります。
最後に、たとえばオーバーフローをチェックしたい場合は、符号付き数字と符号なし数字では異なる方法で行います。
彼は署名されたものと署名されていないものについてのみ尋ねた。なぜ人々がこれに余分なものを追加しているのかわからない。答えを教えてください。
符号なし:負ではない値、つまり0から255のみで構成されます。
符号付き:負の値と正の値の両方で構成されていますが、形式は
そして、この説明は8ビットの数体系についてです。
完全性のためのほんの数点:
この答えは整数表現だけを議論しています。浮動小数点に対して他の答えがあるかもしれません。
負数の表現は変わることがあります。今日使用されている最も一般的な(はるかに今日ではほぼ普遍的です)は2の補数です。他の表現には、1の補数(非常にまれ)および符号付きの大きさ(ほんのわずかしかない - おそらく美術館の作品でのみ使われるこれは、符号表示として上位ビットを単に使用し、残りのビットは数値の絶対値を表します。
2の補数を使用する場合、変数は正数よりも大きい範囲の(1ずつ)負数を表すことができます。これは、ゼロが「正の」数に含まれるため(符号ビットがゼロに設定されていないため)、負の数は含まれないためです。これは、最小の負の数の絶対値を表すことができないことを意味します。
自分の補数または符号付きマグニチュードを使用するときは、ゼロを正数または負数として表すことができます(これは、これらの表現が通常使用されない2つの理由の1つです)。
クラスで学んだことによると、符号付き整数は正との両方の負数を表すことができますが、符号なし整数はのみ非負。
たとえば、8ビットの数値を見てください。
符号なしの値0
から255
符号付き値の範囲は-128
から127
です
ポイント2以外はすべて正しいです。署名付き整数にはさまざまな表記法があります。最初のものを使う実装もあれば、最後のものを使うものもありますが、まったく異なるものもあります。それはすべて、作業しているプラットフォームによって異なります。
別の違いは、異なるサイズの整数間で変換しているときです。
たとえば、符号なしの値を使用して、バイトストリームから整数を抽出している場合(単純にするために16ビットなど)、
i = ((int) b[j]) << 8 | b[j+1]
(おそらく2をキャストする必要がありますnd バイト、しかし、私はコンパイラが正しいことをするだろうと思います)
符号付きの値を使用すると、符号の拡張について心配しなければならなくなります。
i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
一般的に言ってそれは正しいです。なぜあなたが違いを探しているのかについてもっと何も知らずに私は符号付きと符号なしの間の他の区別を考えることができない。
(2番目の質問への答えにおいて)符号ビット(2の補数ではない)だけを使うことによって、あなたは-0で終わることができます。あまりきれいじゃない。
他の人が言ったことに加えて、Cでは、符号なし整数をオーバーフローさせることはできません。動作はモジュラス算術演算として定義されています。符号付き整数をオーバーフローさせることができ、理論的には(現在の主流のシステムでは実際には行われていませんが)、オーバーフローによって障害が引き起こされる可能性があります(おそらくゼロによる除算に似ています)。
符号なし整数は、符号付き整数よりもはるかに特定のトラップにあなたをキャッチする可能性があります。この罠は、上記の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の符号付き整数は数字を表します。 a
とb
が符号付き整数型の変数である場合、標準では、コンパイラが式a+=b
をそれぞれの値の算術和以外のa
に格納することを要求することは決してありません。確かに、算術和がa
に収まらない場合、プロセッサはそれを置くことができないかもしれませんかもしれませんが、規格はコンパイラに切り捨てるか、または折り返すことを要求しません値、または値がその型の制限を超えている場合は、それ以外のことを行います。規格では要求されていませんが、Cの実装では符号付きの値で算術オーバーフローをトラップすることができます。
Cの符号なし整数は、2のべき乗を法として合同な整数の抽象代数的な環として振る舞いますが、より大きな型への変換、またはより大きな型を伴う演算を含むシナリオを除きます。 anyサイズの整数を32ビットの符号なし型に変換すると、その整数mod 4,294,967,296と一致するものに対応するメンバが得られます。 2から3を引いた理由は、4,294,967,295に一致するものに3に一致するものを加えると、2に一致するものが得られるためです。
抽象代数環型はしばしば便利なものです。残念なことに、Cは型が環として振る舞うべきかどうかの決定因子として符号を使います。さらに悪いことに、より大きな型に変換されると、符号なしの値はリングメンバーではなく数値として扱われ、int
より小さい符号なしの値はそれらに対して演算が行われると数値に変換されます。 v
がuint32_t
と等しい4,294,967,294
である場合、v*=v;
はv=4
になります。残念ながら、int
が64ビットの場合、v*=v;
に何ができるのかわかりません。
現状のままで、代数環に関連した振る舞いが欲しい状況では符号なし型を使い、数字を表現したいときは符号付き型を使うことをお勧めします。 Cがそれと同じ方法で区別を作成したのは残念ですが、それが彼らのものです。
組み込みシステムでプログラミングするときは、符号なし整数を使用しなければなりません。ループでは、符号付き整数が不要な場合は、符号なし整数を使用すると、そのようなシステムの設計に必要な安全性が確保されます。
Cの符号付き値と符号なし値の唯一の保証された違いは、符号付き値が負の0または正の値になり、符号のない値は0または正の値になることだけです。問題は、Cが型のフォーマットを定義していないことです(したがって、整数が2の補数であることを知りません)。厳密に言えば、あなたが言及した最初の2つの点は正しくありません。