web-dev-qa-db-ja.com

符号なし整数と符号付き整数の比較演算

このコードスニペットを見る

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)を取得するのですか?

37
Gitmo

異なる整数型間の二項演算は、いわゆる通常の算術変換で定義された「共通」型内で実行されます(言語仕様、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_は問題ありません。

47
AnT

intが32ビットである典型的な実装では、_unsigned int_に変換されたときの-1は4,294,967,295であり、実際には≥1000です。

unsignedワールドで減算を扱う場合でも、1000 - (4,294,967,295) = -4,294,966,295 = 1,001が得られます。

gccunsignedを比較すると、signedは警告を吐き出します。 (警告が表示されない場合は、_-Wsign-compare_フラグを渡します。)

14
kennytm
 #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;
 }

このためには、演算子の優先順位を理解する必要があります

  1. 関係演算子は左から右に機能します...

    if(1000> -1)

intはデフォルトで符号なしの数値として扱われ、符号付きの数値よりも大きいため、まず-1を符号なし整数に変更します

-1は符号なしの数値に変わり、非常に大きな数値に変わります

0
harsh

符号なしの比較、つまり1000と2 ^ 32-1を比較しています。

出力は、printfの%dのために署名されています。

N.B.符号付きオペランドと符号なしオペランドを混在させるときの動作は、コンパイラ固有の場合があります。それらを避け、疑わしいときにキャストを行うのが最善だと思います。

0
Antti Huima

ハードウェアは、署名付きと署名なし、および署名なしと署名なしを比較するように設計されています。

算術結果が必要な場合は、まず符号なしの値をより大きな符号付きの型に変換します。それ以外の場合、コンパイラは、比較が実際に符号なしの値の間であると想定します。

そして、-1は1111..1111として表されるため、非常に大きな量になります...最大...符号なしとして解釈される場合。

0
DigitalRoss

簡単な比較方法を見つけてください。おそらく、符号なし宣言(たとえば[NSArray count])を取り除くことができない場合に便利です。「符号なしint」を「int」に強制するだけです。

私が間違っている場合は修正してください。

if (((int)a)>b) {
    ....
}
0
chenyi1976