C ++列挙型と符号なし整数の比較
-
08-07-2019 - |
質問
現在作業中のコードでこれを見つけ、それが私が抱えているいくつかの問題の原因だと考えました。
ヘッダーのどこかに:
enum SpecificIndexes{
//snip
INVALID_INDEX = -1
};
その後-初期化:
nextIndex = INVALID_INDEX;
および使用
if(nextIndex != INVALID_INDEX)
{
//do stuff
}
コードをデバッグすると、nextIndexの値が意味をなさず(非常に大きかった)、宣言されていることがわかりました:
unsigned int nextIndex;
したがって、INVALID_INDEXの初期設定は、unsigned intをアンダーフローし、巨大な数値に設定していました。私はそれが問題の原因であると仮定しましたが、より詳しく見ると、テスト
if(nextIndex != INVALID_INDEX)
正しく動作していました。つまり、nextIndexが" large + ve value"だった場合、ifの本体は実行されませんでした。
これは正しいですか?これはどうしてですか?列挙値は、変数と同じ型の符号なしintに暗黙的にキャストされているため、同じ方法でラップされていますか?
解決
すべてにはい。 これは有効なコードであり、ライブラリ側のC ++コードとしても一般的に使用されています。現代のC ++ではさらにそうです(初めて見たときは奇妙ですが、実際には非常に一般的なパターンです)。
列挙型は符号付きintですが、暗黙的に符号なしintにキャストされます。これにより、コンパイラによっては警告が表示される場合がありますが、それでも非常に一般的に使用されますが、メンテナーに明確にするために明示的にキャストする必要があります。
他のヒント
enumは、負の値が含まれているかどうか、およびコンパイラがどのように感じるかによって、符号付きまたは符号なし整数型で表されます。この例には負の値が含まれているため、符号付き整数型で表す必要があります。
符号付き型と符号なし型の平等比較は安全で、通常は作成者が意図したことを行います-符号付きの値は最初に符号なしに変換され、その結果はC ++標準で定義され、直感的です(少なくとも、整数が2の補数でない場合を除きます。したがって、それほど直感的ではないかもしれませんが、通常は問題は発生しません。)
順序の比較は、エラーが発生する可能性が高くなります。例:
SpecificIndexes value = INVALID_VALUE;
return (value >= 0);
falseを返しますが、:
unsigned int value = INVALID_VALUE;
return (value >= 0);
trueを返します。特に「値」のタイプが異なる場合、作成者は違いを理解しないことがあります。使用時点ではそれほど明確ではありません。ただし、(値> = 0)はトートロジーであるため、コンパイラは2番目の例について警告する場合があります。
実際、nextValueに割り当てられると、-1は暗黙的に同等の符号なしの値にキャストされます。同等の符号なしは、同じビット単位の表現を持つ値です(111111111111 ...、これは最大の符号なし値です)。
後で、比較ステートメントで、別の暗黙的なキャストが発生します。
これは今すぐ動作しますが、将来的には問題を引き起こす可能性があります。符号付きの値と符号なしの値を混在させることはお勧めできません。
はい、列挙型は署名されていると思います。変更
unsigned int nextIndex;
to
int nextIndex;
そしてあなたのプログラムは動作するはずです。
C ++標準では、実装で列挙型に符号付き型を使用できますが、必須ではありません。したがって、通常、負の数を列挙型に入れることは安全であると想定することはできません。