5

「直感的」とは、与えられたという意味です

int a = -1;
unsigned int b = 3;

(a < b)は 1 に評価される必要があります。

Stackoverflow には、この特定のケースで C コンパイラが符号付き/符号なしの比較について不平を言う理由をすでに尋ねる多くの質問があります。答えは、整数変換規則などに要約されます。それでも、符号付き整数と符号なし整数を比較するときにコンパイラが非常に愚かでなければならない理由はないようです。上記の宣言を使用すると、Why 式は次のようになります

(a < b)

によって自動的に置換されません

(a < 0 || (unsigned int)a < b)

それを適切に行うための単一の機械命令がない場合はどうなりますか?

現在、以前の質問に対して、「符号付き整数と符号なし整数を混在させる必要がある場合、プログラムに問題があります」というコメントがいくつかありました。libc自体が符号付きのみまたは符号なしのみの世界に住むことを不可能にするので、私はそれを買いません(たとえばsprintf()、関数のファミリはint、書き込まれたバイト数として返され、send()返さssize_tれるなど)。

また、以下のコメントで表現されている、符号付き整数から符号なしへの暗黙的(d - '0' < 10U)な変換 ( 「イディオム」) は、明示的なキャスト ( ) と比較して、C プログラマーにいくつかの追加の力を与えるというアイデアを購入できるとは思いません((unsigned int)(d - '0') < 10U)。しかし、確かに、それは台無しにする幅広い機会を開きます.

そして、はい、コンパイラがそれを行うことができないと警告してくれてうれしいです (残念ながら、明示的に要求した場合のみ)。問題は、なぜできないのかということです。通常、標準のルールの背後には正当な理由があるので、ここに何かあるのだろうか?

4

4 に答える 4

6

自動置換はCのセマンティクスとは異なり、変換を正しく使用するプログラムをひどく壊してしまうため、実行できません。例えば:

if (d-'0'<10U)  // false if d is not a digit

提案された置換により、ASCIIスペースおよび他の多くの文字に当てはまります。

ちなみに、この質問は部分的に次のようなものだと思います。

C / C ++と比較して安全な符号付き/符号なしの比較を追加すると、言語または既存のコードが壊れますか?

于 2013-01-23T17:33:53.863 に答える
1

通常の算術変換の規則は、ほとんどすべての二項演算子のオペランドに適用されます。これらは、(少なくともマシンレベルで)等しいタイプを必要とする操作で、異なるサイズと符号の整数タイプの混合を処理するための統一されたフレームワークです。ルールは、一般的なコンピュータアーキテクチャでの実装を可能な限り単純かつ効率的にするように設計されました。特に、signedintとunsignedintの間の変換は、通常、2の補数アーキテクチャでは何も行われず、比較は、署名付きまたは署名なしの単一の命令のままです。

あなたが提案するような例外は、符号付きタイプと符号なしタイプを比較する非常に特殊なケースで可能でした。コストは、式のオペランドを処理するためのルールの不規則性と複雑な実装(署名付き)でした。

Cの設計者はそうしないことを選択しました。その決定を変更すると、限られた利益のために多くの既存のコードが壊れます-他の演算子との一般的な算術変換に遭遇するので、それらに注意する必要があります。

コンパイラは、驚くべき結果をもたらす可能性のある変換について警告します(または警告するようにできます)。そのため、符号やサイズが異なる整数の意図しない組み合わせに驚かされることはありません。キャストを使用して、これをどのように評価するかを正確に表現します。これにより、警告がなくなり、コードの次のリーダーに役立ちます。

于 2013-01-23T18:04:09.847 に答える
1

この場合、必要のない機能にお金を払わなくても、もう一度 C (および C++) にフォールバックすると確信しています。デフォルトの動作で満足できる場合は、明白なコードを書くだけです。ニーズに十分でない場合は、2 部構成の式を自分で作成しますが、追加料金が発生します。コンパイラが常にあなたが提案したことを実行した場合、プログラムで使用される実際の値の範囲が問題を引き起こすことはありませんが、コードのパフォーマンスが低下する可能性があります。

一部のコンパイラは、さまざまな署名の値が比較されている領域に入ったことを知らせるために、便利/正しくない警告を提供します。

于 2013-01-23T17:44:11.617 に答える
0

私が間違っていなければ、これは単なる警告であり、無視してかまいません。

問題は、整数バリアントの範囲です。

符号付き整数は -2147483648 から 2147483648 (+- 1 または 2) までの値を保持できますが、符号なし整数は 0 から 4294967296 までの値を保持できます。

つまり、符号付き整数を符号なし整数と比較すると、内部的に符号が整数の MSB で表されるため、まったく誤った結果になる可能性があります。

例:

-1 という数字と 3,000,000,000 という数字があります。どっちが大きい?明らかに2番目のものと言うかもしれません...しかし、コンピューターの場合、-1は実際には大きくなります。これは、「符号なし」(大きなものを正しく評価するために必要な)-1が最大数として表されるためです。(4294967296)。

それどころか、両方が符号付きとして扱われる場合、符号付き整数の範囲を超えているため、大きな数はかなり大きな負の数になります。

そのため、コンパイラはこの警告を出力します。実際のエラー ケースはかなりまれですが、それでも発生する可能性があります。そして、それはまさにコンパイラがあなたに警告していることです... 2 つの異なる符号の整数を比較すると、予期しないことが起こる可能性があります。

于 2013-01-23T17:32:08.347 に答える