13

私は次の単純なC++コードを持っています:

#include "stdafx.h"
int main()
{
    int a = -10;
    unsigned int b = 10;
    //  Trivial error is placed here on purpose to trigger a warning.
    if( a < b ) {
        printf( "Error in line above: this will not be printed\n" );
    }
    return 0;
}

Visual Studio 2010(デフォルトのC ++コンソールアプリケーション)を使用してコンパイルするとwarning C4018: '<' : signed/unsigned mismatch" on line 7 、期待どおりに表示されます(コードに論理エラーがあります)。

unsigned int b = 10;しかし、私がconst unsigned int b = 10;警告に変わると消えます!そのような行動の既知の理由はどこにありますか?gccに関係なく警告を表示しconstます。

アップデート

コメントから、多くの人が「どういうわけか最適化されているので、警告は必要ない」と提案していることがわかります。残念ながら、私のコードサンプルには警告をトリガーするために注意深く配置された実際の論理エラーがあるため、警告print必要です。ステートメントは、実際には。未満であるにもかかわらず呼び出されません。このエラーはよく知られており、このようなエラーを見つけるために「符号付き/符号なし警告」が正確に発生します。-1010

アップデート

また、コメントから、多くの人が私のコードで符号付き/符号なしの論理エラーを「発見」し、それを説明していることがわかります。そうする必要がない場合-このエラーは純粋に警告をトリガーするために配置され、些細なことであり(それ-10はそう(unsigned int)-10です0xFFFFFFFF-10)、質問はそれについてではありません:)。

4

1 に答える 1

9

これはVisualStudioのバグですが、バグではない側面から始めましょう。

当時適用可能なC++標準のセクション5、注9では、オペランドのビット幅が異なる場合の対処方法について説明してから、オペランドが同じで符号が異なる場合の対処方法について説明します。

...それ以外の場合、符号なし整数型のオペランドのランクが他のオペランドの型のランク以上の場合、符号付き整数型のオペランドは符号なし整数型のオペランドの型に変換されます。

ここで、比較が符号なし算術で動作する必要があることがわかります。ここで、これが値-10に対して何を意味するかを学習する必要があります。

セクション4.6は私達に告げます:

宛先タイプが符号なしの場合、結果の値は、ソース整数と一致する最小の符号なし整数です(モジュロ2 n、nは符号なしタイプを表すために使用されるビット数)。[注:2の補数表現では、この変換は概念的なものであり、ビットパターンに変更はありません(切り捨てがない場合)。— end note] 3デスティネーションタイプが符号付きの場合、デスティネーションタイプ(およびビットフィールド幅)で表現できる場合、値は変更されません。それ以外の場合、値は実装によって定義されます。

ご覧のとおり、特定のかなり高い値(4294967286、またはunsigned int32ビットの数値を想定した場合は0xFFFFFFF6)が10と比較されているため、標準printfは実際には呼び出されないことを保証します。

これで、この場合、診断を必要とする標準にはルールがないことを信じることができます。したがって、コンパイラーは何も発行しません。(実際、-1すべて1のビットパターンを生成することを意図して書き込む人もいます。int配列を反復するために使用する人もいます。これにより、との間の符号付き/符号なしの比較が行わsize_tintます。醜いですが、コンパイルが保証されます。)

現在、VisualStudioは「自発的に」いくつかの警告を発行します。

これにより、すでにデフォルト設定(レベル3)で警告が表示されます。

int a = -10;
unsigned int b = 10;
if( a < b ) // C4018
{
    printf( "Error in line above: this will not be printed\n" );
}

次の場合/W4、警告を受け取る必要があります。警告が再分類されたことに注意してください。警告C4018から警告C4245に変更されました。これは明らかに設計によるものです。比較を壊す論理エラーは、ほとんどの場合、正の正の比較では機能するように見えますが、正の負の比較では機能しない論理エラーよりも危険性が低くなります。

const int a = -10;
unsigned int b = 10;
if( a < b ) // C4245
{
    printf( "Error in line above: this will not be printed\n" );
}

しかし、あなたのケースはまだ異なっていました:

int a = -10;
const unsigned int b = 10;
if( a < b ) // no warning
{
    printf( "Error in line above: this will not be printed\n" );
}

そして、何の警告もありません。(確かに、再試行する必要-Wallがあります。)これはバグです。マイクロソフトそれについて言います:

このフィードバックを送信していただきありがとうございます。これは、C4018警告を発する必要があるシナリオです。残念ながら、この特定の問題は、利用可能なリソースを考えると、次のリリースで修正するのに十分な優先度ではありません。

好奇心から、Visual Studio 2012 SP1を使用して確認しましたが、欠陥はまだあります。警告はありません-Wall

于 2013-03-25T21:40:43.833 に答える