87

私は現在AcceleratedC++を使用していますが、演習2-3で問題が発生しました。

プログラムの概要-プログラムは基本的に名前を取り、アスタリスクの枠内に挨拶を表示します-つまり、こんにちは!*で囲まれています。

演習-サンプルプログラムでは、作成const int者は挨拶とアスタリスクの間のパディング(空白スペース)を決定するために使用します。次に、演習の一環として、読者に、パディングの大きさについてユーザーに入力を求めるように依頼します。

これはすべて簡単に思えます。ユーザーに2つの整数(int)を要求して保存し、これらの整数を使用するようにプログラムを変更して、コンパイル時に作成者が使用した整数を削除しますが、次の警告が表示されます。

演習2-3.cpp:46:警告:符号付き整数式と符号なし整数式の比較

いくつかの調査の結果、コードが上記の整数(int)の1つを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、タイプですが、作成者のコードを使用しても問題が発生しなかったのに、なぜこの問題が発生するのでしょうか。さらに、Accelerated C ++を完了した可能性のある人には、これについては本の後半で説明しますか?string::size_typeconst int

私はLinuxMintを使用してGeany経由でg++を使用していますが、それが役立つか、違いを生む場合(私が読んだように、それが何でstring::size_typeあるかを判断するときに可能です)。

4

6 に答える 6

115

この問題を回避するために、通常、変数をサイズとして宣言するか、サイズと比較するunsignedかどうかを宣言することをお勧めします。size_t可能な限り、比較する正確なタイプを使用してください(たとえば、の長さstd::string::size_typeと比較する場合に使用しますstd::string)。

コンパイラは、符号付きと符号なしの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();
}
于 2010-09-07T17:09:54.043 に答える
9

昨日、Accelerated C++ で問題 2-3 に取り組んでいるときにまったく同じ問題が発生しました。重要なのは、(ブール演算子を使用して) 比較するすべての変数を互換性のある型に変更することです。この場合、それはstring::size_type(またはunsigned int、ただし、この例では前者を使用しているため、2 つが技術的に互換性があるとしても、それをそのまま使用します) を意味します。

あなたが正しく指摘したように、元のコードでは c カウンター (本のセクション 2.5 の 30 ページ) に対して正確にこれを行ったことに注意してください。

この例をより複雑にしているのは、さまざまなパディング変数 (padsides と 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

string::size_type前の条件で、forループ内で変数 r を a として初期化しないと、エラーが発生することに注意してください。したがって、次のようなものを使用して for ループを初期化する必要があります。

    for (string::size_type r=0; r!=rows; ++r)   //If r and rows are string::size_type, no error!

したがって、基本的に、string::size_type変数をミックスに導入すると、そのアイテムに対してブール演算を実行するときはいつでも、警告なしでコンパイルできるように、すべてのオペランドに互換性のある型が必要です。

于 2014-01-07T16:25:51.550 に答える
6

符号付き整数と符号なし整数の重要な違いは、最後のビットの解釈です。符号付きタイプの最後のビットは、数値の符号を表します。つまり、次のようになります。

0001 は 1 の署名付きおよび未署名 1001 は -1 の署名付きおよび 9 の未署名

(説明を明確にするために、補数の問題全体を避けました!これは、メモリ内でintが正確に表現される方法ではありません!)

-1 と比較するか、+9 と比較するかによって違いが生じることが想像できます。多くの場合、プログラマーは int のカウントを unsigned として宣言するのが面倒です (for ループ ヘッド fi を肥大化させます) int では、符号ビットが噛み付くまで 2^31 までカウントする必要があるため、通常は問題になりません。そのため、これは単なる警告です。「int」の代わりに「unsigned」と書くのが面倒だからです。

于 2010-09-07T17:32:32.910 に答える
4

極端な範囲では、unsigned int が int よりも大きくなる可能性があります。
したがって、コンパイラは警告を生成します。これが問題ではないことが確実な場合は、型を同じ型に自由にキャストして、警告が表示されないようにしてください (見つけやすいように C++ キャストを使用してください)。

または、変数を同じ型にして、コンパイラが文句を言わないようにします。
つまり、負のパディングを行うことは可能ですか? その場合は、int として保持します。それ以外の場合は、おそらく unsigned int を使用して、ユーザーが負の数を入力する状況をストリームにキャッチさせる必要があります。

于 2010-09-07T17:13:33.190 に答える