2011-05-29 5 views
10

これは、C++でプログラミングするときに私に起こったことの中で最も変わったことです。勉強しようとすると消えるバグ

これは私のメインのファイルです:

#include <iostream> 
#include "lib/utils.h" 

using namespace std; 

int main(int argc, const char *argv[]) { 
    cout << bin2dec(101000010); 
    return 0; 
} 

、これは/ libにutils.cppです:

#include <iostream> 
#include "utils.h" 

int bin2dec(int bin) { 
    // 101000010 
    int dec; 
    //std::cout << ""; // If you uncomment this, it works. 
    for (int i = 1; bin > 0; i *= 2, bin /= 10) { 
     if (bin % 2 == 1) { 
      dec += i; 
     } 
    } 
    return dec; 
} 

プログラムは警告なしでコンパイルし、実行したとき、それは450を出力します。 450は10進数で101000010ではありません。最初の奇妙なことは、482と322の差が正確に128であるということです。これは変換しようとする2進数で起こります。しかし、本当に奇妙なのは、bindecの値をforの中に出力しようとすると、関数をデバッグしようとすると、突然正しく動作するようになりました。

基本的には何らかの理由で、関数が返される前に何かstd::coutが返されても動作します。そうしないと、結果に128が追加されます。

私はG ++ 4.6.0を使用して、次のようにコンパイルしています:

g++ -c -D NDEBUG -O2  -o 10.o 10.cpp 
g++ -c -D NDEBUG -O2  -o lib/utils.o lib/utils.cpp 
g++ -o 10 -Wl,-S 10.o lib/utils.o lib/menu.o 
+0

+1よく尋ねられる質問 –

+0

これは非常に一般的です。未定義の動作の世界へようこそ。 –

+0

@Dougおそらくあなたは私にその質問が何であるか説明することができますか? –

答えて

23

あなたはdecを初期化していません。

あなたはあなたの関数でゼロに decを初期化する必要が
int dec = 0; 
+0

クラップ、忘れました。今私は馬鹿のように感じる。しかたがない。ありがとう! –

+2

@ジェラードあなたは間違いを犯してはいけません:あなたが作ったミスの「愚かな」:私たちはすべてそこにいて、私たちはすべて再びそこに行きます。 – Wipqozn

0

機能のすべての操作がオンになっているので、かなり単に、あなたの問題は、おそらくスタックME-するスタックスマッシングまたはヒープを叫びますスタックこの種の問題に陥ることはありませんが、プログラム内の他の場所で不定な動作を呼び出す必要はありません。

編集:ああ、例えば、decの初期化から始めることができます。

3
int dec; 

decを作成しませんが、決してそれを(0のような)の初期値を与えます。その後、値を追加して、ランダムな結果に終わります。

3

int dec = 0; 

それを初期化しないことで、それが何であれ、ランダムなCRUDで始まり、変数の場所でメモリ内にあります。そしてcout <<への呼び出しは、その領域に何が荒れているのか、それゆえの変更に影響します。ところで、あなたのコードを試したとき、私は450を得ていませんでした。私はこれの例を示す134514688を得ていた。

16

小さなバグはdec変数を初期化していないことです。

大きなバグは、コンパイル時に-Wall-O2を追加しないことです(書き込みするプログラムが複雑になるため、苦労するでしょう)。

-Wallはすべての警告を有効にし、-O2には最適化が必要です(最適化には、初期化されていない変数に関する警告が表示されます)。

+2

私にそれを打つ。常に-Wallを使用してください。時々 - 壁だけでは不十分です。 -Wallと最適化を使ってコンパイルすると、初期化されていない変数などが見つかります。 –

+0

@David Hammen:True ...より多くの警告を表示するには、最適化を要求することが重要です。私の返信を編集しました。 – 6502

+0

Wall *はすべての警告を有効にしません。壁がつかまらないというかなりの警告があります。私は、-Wall -Wold-style-cast -Wowloaded-virtual -Wshadowを使用します。私は-WeffC++を追加すると、標準ライブラリのGNUの実装からそうしたことが起こることはあまりありませんでした。 –