web-dev-qa-db-ja.com

警告-符号付き整数式と符号なし整数式の比較

私は現在Accelerated C++で作業しており、演習2-3で問題に遭遇しました。

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

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

これはすべて簡単だと思うので、ユーザーに2つの整数(int)を要求して保存し、これらの整数を使用するようにプログラムを変更します。 ;

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

いくつかの調査の後、コードは上記の整数(int)の1つと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

上のコードは関連するビットです。cstring::size_typeタイプです。グリーティングの長さがわからないためです。 const intを使用すると問題が発生しますか?さらに-完了した可能性のある人Accelerated C++-これについては本の後半で説明しますか?

私がLinux MintでGeanyを介してg ++を使用しているのは、それが(string::size_typeが何であるかを判断するときに読むことができるように)助けになるか、または違いを生む場合です。

62
Tim Harrington

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

コンパイラは、符号付き型と符号なし型の範囲が異なるため、符号付き型と符号なし型の比較に関する警告を出し、それらを互いに比較すると、驚くべき結果が得られます。このような比較を行う必要がある場合、おそらく変換が有効であることを確認した後に、値の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();
}
85

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

元のコードでは、あなたが正しく指摘したように、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

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

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

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

7
neuronet

符号付き整数と符号なし整数の重要な違いは、最後のビットの解釈です。符号付き型の最後のビットは、数値の符号を表します。たとえば、次のとおりです。

0001は1符号付き、符号なし1001は-1符号付き、9は符号なし

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

-1と比較した場合と+9と比較した場合に違いがあることを想像できます。多くの場合、プログラマはintのカウントを符号なしとして宣言するのが面倒です(forループヘッドf.i.を膨らませます)。それが警告にすぎない理由です。私たちは「int」ではなく「unsigned」を書くのが面倒だからです。

4
AndreasT

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

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

4
Martin York

主な問題は、基礎となるハードウェアであるCPUには、2つの符号付き値を比較するか、2つの符号なし値を比較するための命令しかありません。符号なしの比較命令に符号付きの負の値を渡すと、大きな正の数として処理されます。したがって、すべてのビットがオン(2の補数)のビットパターン-1は、同じビット数の最大符号なし値になります。

8ビット:-1符号付きは、255符号なし16ビットと同じビットです:-1符号付きは、65535符号なしなどと同じビットです。

したがって、次のコードがある場合:

int fd;
fd = open( .... );

int cnt;
SomeType buf;

cnt = read( fd, &buf, sizeof(buf) );

if( cnt < sizeof(buf) ) {
    perror("read error");
}

ファイル記述子が無効(またはその他のエラー)になったためにread(2)呼び出しが失敗した場合、cntは-1に設定されます。符号なしの値であるsizeof(buf)と比較する場合、0xffffffffはsizeof()some(合理的で、最大サイズに調整されていない)データ構造なので、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++はこれをうまく行かないので、ここにある他の多くの回答で述べられているように、型の周りのすべてについて非常に明確にする必要があります。

0
Gregg Wonderly

または このヘッダーライブラリ を使用して、次のように記述します。

// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))

署名付き/署名なしまたは異なるサイズを気にしません

0
burner