警告 - 署名された整数と署名されていない整数式の比較
-
01-10-2019 - |
質問
私は現在取り組んでいます 加速C ++ 演習2-3で問題に遭遇しました。
プログラムの簡単な概要 - プログラムは基本的に名前を取り、アスタリスクのフレーム内に挨拶を表示します - つまり、こんにちは! *sに囲まれた囲まれた。
エクササイズ - 例プログラムでは、著者が使用します const int
挨拶とアスタリスクの間のパディング(空白スペース)を決定します。次に、演習の一環として、読者に、パディングの大きさについてユーザーに入力を依頼するように頼みます。
これはすべて簡単に思えますが、私は先にユーザーに2つの整数を尋ねます(int
)そしてそれらを保存し、プログラムを変更してこれらの整数を使用し、著者が使用しているものを削除します。
Exercise2-3.CPP:46:警告:署名された整数と署名されていない整数式の比較
いくつかの調査の後、コードが上記の整数の1つを比較しようとしているためです(int
)aに string::size_type
, 、大丈夫です。しかし、私は疑問に思っていました - これは私が整数の1つをに変えるべきだということですか unsigned int
?整数が署名されているのか、署名されていないのかを明示的に述べることが重要ですか?
cout << "Please enter the size of the frame between top and bottom you would like ";
int padtopbottom;
cin >> padtopbottom;
cout << "Please enter size of the frame from each side you would like: ";
unsigned int padsides;
cin >> padsides;
string::size_type c = 0; // definition of c in the program
if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs
上記は関連するコードのビットです c
タイプです string::size_type
挨拶がどれくらいの期間であるかわからないからです - しかし、なぜ著者のコードが使用するときに問題が発生しなかったのに、なぜこの問題が発生するのですか const int
?さらに - 完了した可能性のある人に 加速C ++ - これは本の後半で説明しますか?
G ++を介してG ++を使用してLinuxミントを使用しています。 string::size_type
は)。
解決
通常、変数を次のように宣言することは良い考えです unsigned
また size_t
この問題を回避するために、サイズと比較される場合。可能な場合はいつでも、比較する正確なタイプを使用します(たとえば、使用してください std::string::size_type
と比較する場合 std::string
'sの長さ)。
コンパイラは、署名されたタイプと署名されたタイプと署名されていないINTの範囲が異なるため、署名されていないタイプの比較に関する警告を発します。このような比較を行う必要がある場合は、おそらくコンバージョンが有効であることを確認するために、おそらくチェックした後、値の1つを他のタイプに明示的に変換する必要があります。例えば:
unsigned u = GetSomeUnsignedValue();
int i = GetSomeSignedValue();
if (i >= 0)
{
// i is nonnegative, so it is safe to cast to unsigned value
if ((unsigned)i >= u)
iIsGreaterThanOrEqualToU();
else
iIsLessThanU();
}
else
{
iIsNegative();
}
他のヒント
昨日、まったく同じ問題があり、C ++の加速で問題2-3で作業しました。重要なのは、(ブールオペレーターを使用して)互換性のあるタイプと比較するすべての変数を変更することです。この場合、それは意味します string::size_type
(また unsigned int
, 、しかし、この例は前者を使用しているので、2つが技術的に互換性があるにもかかわらず、私はそれに固執します)。
あなたが正しく指摘したように、彼らの元のコードでは、彼らはCカウンター(本のセクション2.5の30ページ)に対して正確にこれを行ったことに注意してください。
この例をより複雑にしているのは、さまざまなパディング変数(Padsides and Padtopbottom)とすべてのカウンターが必要であることです。 また に変更されます string::size_type
.
あなたの例を把握して、あなたが投稿したコードは次のようになります:
cout << "Please enter the size of the frame between top and bottom";
string::size_type padtopbottom;
cin >> padtopbottom;
cout << "Please enter size of the frame from each side you would like: ";
string::size_type padsides;
cin >> padsides;
string::size_type c = 0; // definition of c in the program
if (r == padtopbottom + 1 && c == padsides + 1) { // where the error no longer occurs
以前の条件では、変数rを初期化しなかった場合、エラーが発生することに注意してください。 string::size_type
の中に for
ループ。したがって、次のようなものを使用して、forループを初期化する必要があります。
for (string::size_type r=0; r!=rows; ++r) //If r and rows are string::size_type, no error!
したがって、基本的には、aを紹介したら string::size_type
ミックスに変数は、そのアイテムでブール操作を実行したいときはいつでも、すべてのオペランドには、警告なしにコンパイルするために互換性のあるタイプが必要です。
署名されたINTと署名されていないINTの重要な違いは、最後のビットの解釈です。署名されたタイプの最後のビットは、数字の記号を表します。つまり、例:
0001は1署名され、署名されていない1001は-1署名され、9は署名されていません
(説明を明確にするために補完的な問題全体を避けました!これは、INTがメモリでどのように表現されるかではありません!)
-1または+9と比較するかどうかを知ることは違いを生むと想像できます。多くの場合、プログラマーは、intsを符号なしでカウントすることを宣言するのが面倒です(forループヘッドFiの膨張)それは通常問題ではありません。INTがサインビットが噛むまで2^31にカウントする必要があるためです。それがそれがただの警告である理由です。私たちは「int」の代わりに「署名されていない」と書くにはあまりにも怠惰だからです。
極端な範囲では、署名されていないINTがINTよりも大きくなる可能性があります。
したがって、コンパイラは警告を生成します。これが問題ではないと確信している場合は、警告が消えるようにタイプを同じタイプにキャストしてください(C ++キャストを使用して、簡単に見つけることができます)。
または、コンパイラが文句を言うのを止めるために、変数を同じタイプにします。
つまり、ネガティブなパディングをすることは可能ですか?もしそうなら、それをintとして保ちます。それ以外の場合は、おそらく署名されていないINTを使用し、ユーザーが負の数でタイプする状況をストリームにキャッチさせる必要があります。
または使用します このヘッダーライブラリ そして書く:
// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))
署名/署名または異なるサイズを気にしないでください
主な問題は、基礎となるハードウェアであるCPUには、2つの署名値を比較するか、2つの署名されていない値を比較する手順のみがあることです。署名されていないマイナス値に署名されていない比較命令に合格すると、それを大きな正の数字として扱います。したがって、-1、すべてのビットがオン(2つの補数)を持つビットパターンは、同じビット数の最大符号なしの値になります。
8ビット:-1署名されているのは255の符号なしの16ビットと同じビットです:-1署名は65535 Unsignedなどと同じビットなどです。
したがって、次のコードがある場合:
int fd;
fd = open( .... );
int cnt;
SomeType buf;
cnt = read( fd, &buf, sizeof(buf) );
if( cnt < sizeof(buf) ) {
perror("read error");
}
ファイル記述子が無効になっている(または他のエラー)がcntが-1に設定されているため、読み取り(2)コールが失敗した場合に発見されます。 0xfffffffffがsizeof(妥当であり、最大サイズとcutesedされていない)データ構造に大きくないため、sizeof(buf)のsizeof(buf)と比較すると、if()ステートメントはfalseになります。
したがって、署名/符号なしの警告を削除するには、上記を書く必要があります。
if( cnt < 0 || (size_t)cnt < sizeof(buf) ) {
perror("read error");
}
これは問題について大声で話します。
1. Introduction of size_t and other datatypes was crafted to mostly work,
not engineered, with language changes, to be explicitly robust and
fool proof.
2. Overall, C/C++ data types should just be signed, as Java correctly
implemented.
非常に大きいため、署名された値タイプを見つけることができない値がある場合、選択した言語では、プロセッサが小さすぎるか、大きすぎる値の値を使用しています。お金と同様に、すべての数字がカウントされる場合、ほとんどの言語で使用するシステムがあり、精度の無限の数字を提供します。 C/C ++はこれをうまく行いません。ここで他の多くの答えで言及されているように、タイプの周りのすべてについて非常に明示的でなければなりません。