このコードスニペットを見る
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
ここで何が起こっているのか分かりません。ここで>演算子はどのように機能しますか? 「a」が「b」よりも小さいのはなぜですか?それが実際に小さい場合、なぜ差として正の数(1001)を取得するのですか?
異なる整数型間の二項演算は、いわゆる通常の算術変換で定義された「共通」型内で実行されます(言語仕様、6.3.1.8を参照)。あなたの場合、「共通」タイプは_unsigned int
_です。これは、int
オペランド(b
)が比較の前に、また減算を実行するために_unsigned int
_に変換されることを意味します。
_-1
_が_unsigned int
_に変換されると、結果は可能な限り最大の_unsigned int
_値(_UINT_MAX
_と同じ)になります。言うまでもなく、これは符号なしの_1000
_値より大きくなります。つまり、_a > b
_は実際にfalseであり、a
は実際にsmall_(unsigned) b
_と比較。コード内のif
は、実験で観察したelse
ブランチに解決されるはずです。
同じ変換規則が減算に適用されます。 _a-b
_は実際にはa - (unsigned) b
として解釈され、結果の型は_unsigned int
_です。 _%d
_はsigned値でのみ機能するため、このような値は_%d
_形式指定子では出力できません。 _%d
_で印刷しようとすると、未定義の動作が発生します。そのため、印刷された値は(実際には論理的な決定論的説明があるとしても)C言語の観点からはまったく意味がありません。
編集:実際、未定義の動作部分について間違っている可能性があります。 C言語仕様によると、対応する符号付き整数型と符号なし整数型の範囲の共通部分は、同じ表現を持つ必要があります(脚注31「関数への引数としての互換性」を意味します)。したがって、上記のように_a - b
_式の結果は符号なし_1001
_であり、何かが欠けていない限り、この特定の符号なしの値を_%d
_指定子で印刷することは正当です。 int
の正の範囲内。 _(unsigned) INT_MAX + 1
_と_%d
_を印刷することは未定義になりますが、_1001u
_は問題ありません。
int
が32ビットである典型的な実装では、_unsigned int
_に変換されたときの-1は4,294,967,295であり、実際には≥1000です。
unsigned
ワールドで減算を扱う場合でも、1000 - (4,294,967,295) = -4,294,966,295 = 1,001
が得られます。
gcc
とunsigned
を比較すると、signed
は警告を吐き出します。 (警告が表示されない場合は、_-Wsign-compare
_フラグを渡します。)
#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)
intはデフォルトで符号なしの数値として扱われ、符号付きの数値よりも大きいため、まず-1を符号なし整数に変更します
-1は符号なしの数値に変わり、非常に大きな数値に変わります
符号なしの比較、つまり1000と2 ^ 32-1を比較しています。
出力は、printfの%dのために署名されています。
N.B.符号付きオペランドと符号なしオペランドを混在させるときの動作は、コンパイラ固有の場合があります。それらを避け、疑わしいときにキャストを行うのが最善だと思います。
ハードウェアは、署名付きと署名なし、および署名なしと署名なしを比較するように設計されています。
算術結果が必要な場合は、まず符号なしの値をより大きな符号付きの型に変換します。それ以外の場合、コンパイラは、比較が実際に符号なしの値の間であると想定します。
そして、-1は1111..1111として表されるため、非常に大きな量になります...最大...符号なしとして解釈される場合。
簡単な比較方法を見つけてください。おそらく、符号なし宣言(たとえば[NSArray count])を取り除くことができない場合に便利です。「符号なしint」を「int」に強制するだけです。
私が間違っている場合は修正してください。
if (((int)a)>b) {
....
}