署名されていない整数と署名された整数の比較操作
質問
このコードスニペットを参照してください
int main()
{
unsigned int a = 1000;
int b = -1;
if (a>b) printf("A is BIG! %d\n", a-b);
else printf("a is SMALL! %d\n", a-b);
return 0;
}
これにより出力が得られます:a is small:1001
ここで何が起こっているのかわかりません。 >オペレーターはここでどのように機能しますか?なぜ「b」よりも「a」が小さいのですか?それが本当に小さい場合、なぜ私は違いとして正の数(1001)を得るのですか?
解決
異なる積分タイプ間のバイナリ操作は、いわゆる呼び出しによって定義される「共通」タイプ内で実行されます 通常の算術変換 (言語仕様、6.3.1.8を参照)。あなたの場合、「共通」タイプはです unsigned int
. 。この意味は int
オペランド(あなたの b
)に変換されます unsigned int
比較の前、および減算を実行する目的のために。
いつ -1
に変換されます unsigned int
結果は可能な限り最大です unsigned int
値(と同じ UINT_MAX
)。言うまでもなく、それはあなたの署名よりも大きくなるでしょう 1000
価値、それを意味します a > b
確かに偽です a
確かに 小さな に比べ (unsigned) b
. 。 if
コードでは解決する必要があります else
ブランチ。これはあなたがあなたの実験で観察したものです。
同じ変換ルールが減算に適用されます。君の a-b
本当に解釈されます a - (unsigned) b
結果にはタイプがあります unsigned int
. 。そのような値を印刷することはできません %d
以来、フォーマット仕様 %d
一緒に機能します 署名 値。それを印刷しようとするあなたの試み %d
未定義の動作をもたらすため、印刷されている値は(実際には論理的な決定論的な説明がありますが)、C言語の観点からは完全に無意味です。
編集: 実際、私は未定義の動作の部分について間違っている可能性があります。 C言語の仕様によれば、対応する署名された署名されていない整数型の範囲の共通部分には、同一の表現があります(脚注31によると、「関数の議論としての互換性」)。だから、の結果 a - b
表現は署名されていません 1001
上記のように、そして私が何かが足りないのでなければ、この特定の署名の価値を印刷することは合法です %d
指定器は、の正の範囲内に収まるため int
. 。印刷 (unsigned) INT_MAX + 1
と %d
未定義ですが 1001u
結構です。
他のヒント
典型的な実装について int
32ビット、-1はanに変換されます unsigned int
4,294,967,295で、実際には1000以上です。
減算をandで扱っても unsigned
世界、 1000 - (4,294,967,295) = -4,294,966,295 = 1,001
これがあなたが得るものです。
それが理由です gcc
比較すると警告が吐き出します unsigned
と signed
. 。 (警告が表示されない場合は、 -Wsign-compare
国旗。)
署名のない比較、つまり1000〜2^32-1を比較しています。
Printfの%Dのために出力が署名されます。
nb署名と署名のないオペランドをミックスすると、動作がコンパイラ固有の場合があります。それらを避け、疑わしいときにキャストをすることが最善だと思います。
比較する簡単な方法を見つけてください。署名されていない宣言を取り除くことができない場合(たとえば、[nsarray count])、「符号なしのint」を「int」に強制するだけです。
私が間違っている場合は私を修正してください。
if (((int)a)>b) {
....
}
ハードウェアは、署名された署名と署名のない署名と署名のないものを比較するように設計されています。
算術結果が必要な場合は、符号なしの値を最初に大きな署名型タイプに変換します。それ以外の場合、コンパイラは、比較が実際に署名されていない値の間であると想定しています。
-1は1111..1111として表されるため、非常に大量...最大の量...署名されていないと解釈されると。
#include<stdio.h>
int main()
{
int a = 1000;
signed int b = -1, c = -2;
printf("%d",(unsigned int)b);
printf("%d\n",(unsigned int)c);
printf("%d\n",(unsigned int)a);
if(1000>-1){
printf("\ntrue");
}
else
printf("\nfalse");
return 0;
}
このためには、オペレーターの優先順位を理解する必要があります
リレーショナルオペレーターは左から右に動作します...だからそれが来るとき
if(1000> -1)
次に、defaultはデフォルトでは符号なしの数値として扱われ、署名された数値よりも大きいため、まず-1が符号なし整数に変更されます。
-1は署名のない数に変わり、非常に大きな数に変わります
a> bを比較している間、aは符号なしintタイプで、bはintタイプです、 Bは、署名されていないINTにキャストされたタイプです したがって、署名されたint値-1はunsigned **(範囲:0から(2^32)-1)**の最大値に変換されます。したがって、それ以外のループ printf( "a is small!%d n"、ab); 実行された。