C・C++Debug日記3

ブレークポイントがヒットしない

1.現象
必ず通る箇所にブレークポイントを置き、プログラムを実行させた途端に、ブレークポイントの赤く塗られた●マークが、 ただの赤線の○マークになり、○の中に「!」が表示されるようになった。
同じような現象がたくさんあるらしい
最悪MS側のバグの可能性もある
2.解決方法
ツール→オプション→→デバッグ
で「元のバージョンと完全に一致するソースファイルを必要とする」のチェックボックスをオフにする。
3.Link
まったく同じ解決方法
MSのバグ情報
掲示板1
掲示板2
掲示板3

VS2008で引数の追加が反映されない

1.現象
ある関数を作成後に新たに引数を追加したが Visual Studio 内のクラスビューには反映されない。
2.解決方法
下の「VS2008でメンバ関数追加ウィザードが使えない」と同様にncbファイルを削除する。

VS2008でメンバ関数追加ウィザードが使えない

1.ErrorMessageDialog

Microsoft Visual Studio

新しいコード要素を返すのに失敗しました。構文エラーが考えられます。新しい要素名は aaa です。

OK

2.現象
Visual Studio 2008 でメンバ関数追加ウィザードを使用してメンバ関数を追加しようとすると上記のエラーメッセージダイアログが表示されて追加ができない。
3.原因
不明
4.解決方法
Visual Studio 2008を閉じてからプロジェクトフォルダ内にある「プロジェクト名.ncb」ファイルを削除する。Visual Studio 2008を再起動すれば.ncbファイルは再生成されるので削除しても問題はない。
5.Link
まったく同じ説明

ファイル保存用フラグが定義できない

0.Error Message
エラー 1 error LNK2005: "bool AnchorDataSaveFlag" (?AnchorDataSaveFlag@@3_NA) は既に CalculateTask.obj で定義されています。
1.現象
MFC設定のプログラムでC&C++/テンプレのヘッダーファイルを利用すると上記のエラーメッセージが出る。
2.原因
変数の定義の仕方がグローバル変数の定義のやり方のままであったためMFCでは使用できなかった。MFCはグローバル変数禁止!
3.解決方法
新しくクラスを作る。

並べ替えプログラムが動作しない

1.現象
並べ替えプログラムを使用するとプログラム自体が落ちる。デバッグで調べると特定の部分で動作がループしている。ループの時点では並び替えも完了していない。クイックソートアルゴリズムを使用。
2.原因
  1. (遠因)今回は配列値を直接比較するのではなく二次配列を変換してから比較、値の入れ替えを行った。
  2. クイックソートアルゴリズムの肝である軸要素以上の値が見つかるまで検索する部分で
// 枢軸以上の値が見つかるまで右方向へ進めていく
while( IDist < PivDist )
{
++i;
IDist = // 二次配列の変換[i];
} 
とする部分を
// 枢軸以上の値が見つかるまで右方向へ進めていく
while( IDist < PivDist )
{
IDist = // 二次配列の変換[i];
++i;
} 
と順番を逆にしてしまった。これによって配列値の変更が一歩分遅れ、while文を抜ける値が得られた場合でも指定子iが余計に増加してしまう結果となった。
3.教訓
実は最初にコーティングした際おかしくなるかもしれないと思っていたがwhileループ内ので完結する話だと考えてしまいスルーしてしまった。こんなに重大なミスにつながるとは思えなかった。
変数iが頻繁に変更されることに心理的抵抗を覚えたのも事実。こういったミスの原因になりかねないのであくまでもアルゴリズム通りに動作するようにコードは作成するべきだと思った。

配列の重複部分削除について

1.教訓
配列を繰り返し検索し、一致したものがなければ改めて新しい配列に格納するわけだが、その際繰り返し条件と格納条件が異なることに注意。
例えば7番目の配列の内容を0~6番目まで検索するが検索の繰り返しの段階で格納まで行うと
Arr[7] != Arr[0]
で即格納になってしまう。実はArr[7] == Arr[2]であったとしても!
そこでArr[7] == Arr[0~6]ならtrueを返すなどの繰り返し処理をあらかじめ作り、そのあとに返り値の値によって格納を決める処理を作る。検索はあくまでも最後まで(または一致する値が見つかるまで)行ってから判断する。

処理結果を配列に格納しようとしたら配列数がとんでもないことになった

1.現象
上記のとおり。100個程度を予想したら1500個ほど出てきた。
2.原因
(1)While文の中のfor文の使い方ミス
While文である条件を指定し、その中にfor文入れて配列に格納した。その際
for( int i = 0; i < exNum ; i++ ){
exArray[ i ] = 100;// 障害物の属性
}
の様に配列指定にiを用いてしまった。これによってWhileの繰り返しごとに配列exArrayの同じ場所に格納してしまっていた。
(2)ファイルへの保存の際の繰り返し回数指定ミス
最終的に値を格納された配列の数を指定する変数とは異なる変数でfor文を回して保存を行ってしまった。あり得ない値(0とか)が格納されていたらこの原因かも。

ハンドルされていない例外7

1.ErrorMessageDialog
~~.exe の 0x7861d9fe (mfc90d.dll) でハンドルされていない例外が発生しました: 0xC0000005: 場所 0xfffffffc を読み込み中にアクセス違反が発生しました。
2.現象
複数宣言されていたオブジェクトの数をさらに増やしたくてコーディング中発生。初期化のfor( int i = 0; i < NUM; i++ ) のNUMを増やしたら発生。
3.原因
オブジェクトの宣言部分の数と初期化のNUMがあっていなかった。
4.解決方法
宣言数を増やした。
5.教訓
やはり「ハンドルされていない例外」のエラーは
  1. 存在しない変数、配列、オブジェクトにアクセスが起こった場合
  2. 変数に定義以上の値が入っている場合
  3. MFCにおいて設定した画面以上に画像がはみ出てしまった場合
などに起きている。

ハンドルされていない例外6

1.ErrorMessageDialog
~~.exe の 0x0041d0cf でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x8000061a に書き込み中にアクセス違反が発生しました。
2.現象
  1. MFCのプログラムにおいて連続処理を数回行った後ある特定の地点で起きる。
3.原因
  1. 直接の原因はあるクラスのメンバ変数( m_pt )の値が-214783100などのありえない値をとったため。
  2. m_ptの値を変更する過程でエラーが発生した。
4.原因候補
  1. メンバ変数を使用するクラスは複数宣言されているので複数のm_ptが存在しアクセスにミスる。⇒まちがい
  2. メンバ変数m_ptへの値格納にミスが発生している。⇒十分接近してからも最後に一回分の移動を行っている。dHogeの値が怪しい。⇒正解
  3. (上のミスと似ているが)本来必要のない時点でm_ptの値を変化させているのでおかしな値が格納される。⇒まちがい
5.原因(確定版)
m_ptの値を変化させる変数dHogeは
dHoge = MoveSpeed * ( dRadius_x / dRadius_Range );
と式内に割り算を含んでいた。処理の過程において割り算の分母である dRadius_Range の値が=0になることがあった。
そのときdHogeは1.#IND000000000000とありえない値をとっていた。これがさらにm_ptに
m_pt = m_pt + dHoge;
とされてしまい上記の-214783100という値をとってしまった。
6.解決方法(試行錯誤版)
【失敗】
  1. m_ptがおかしな値を得たら排除する。⇒おかしな値は頻繁に発生する模様。プログラムが起動しなくなった。
  2. エラー周辺でデバッグステップ実行⇒ソースコードを表示できないエリアに突入しわけわかめ。
  3. m_ptの値の変化をすべてチェック⇒171箇所もあり眠くなったw
【成功】
  1. 必要のないm_ptの変更を行わないよう適当な部分でbreakを入れる。⇒同じような処理の部分でこれがそもそも必要ない例がある。なぜ?
  2. リビルド⇒あるとき突然これで解決した。なぜ?
7.解決方法(確定版)
分母dRadius_Rangeの値によって場合わけ。
8.教訓
  1. 今回のバグはかなり厳しかった。延べ13時間以上かかったと思う。
  2. m_ptがおかしいと気づくまで5h。dHogeが怪しいと気づくまでさらに8h。
  3. 変数の値がおかしい場合はその変数を変更する場所がもっとも怪しい場所というのは理論的に当然わかること。
  4. 今回自分はm_ptの値の変化をすべてチェック⇒171箇所もあり眠くなったwなどという態度でありこれでは13時間以上かかるのも無理ない。
  5. もっと自分の理論を信じて調査していれば早く解決できると思った(精神論ぽいけど)。

ハンドルされていない例外5

1.ErrorMessage
~~.exe の 0x004146e7 でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x00001f38 を読み込み中にアクセス違反が発生しました。
2.原因
オブジェクトをポインタとして宣言したが、肝心のクラス型のオブジェクトの宣言、ポインタの格納を行っていなかった。
3.解決方法(例文)
CJusho cj;
CJusho *pcj;
pcj = &cj;
以上の操作を行って初めてポインタを使用できる。
4.教訓
  1. “ハンドルされていない例外”は存在しない配列、変数などに参照が行われた場合発生すると思われる。デバッガで指定された変数がプログラム上存在するのか確かめる必要がある。
  2. クラスをポインタとして使用するのはメモリの確保、解放を自分で管理しなければいけないのでリスクが発生する。ポインタを使用する明確な理由がない限り使わない方が良いかも。

sqrtについて

1.ErrorMessage
error C2668: 'sqrt' : オーバーロード関数の呼び出しを解決することができません。(新機能 ; ヘルプを参照)
2.原因
sqrtは整数値を引数にできない。
3.解決方法
引数に1.0でもかけておく。
4.Link
クリティカルに説明したページ

CStringについて

1.現象
オブジェクト化されたプログラムを再利用するため他のプログラムでとあるクラスを読み込んだところ、CString関係でエラーメッセージが沢山発生。
2.ErrorMessage
error C2065: 'CString' : 定義されていない識別子です。
error C2061: 構文エラー : 識別子 'CString'
error C4430: 型指定子がありません - int と仮定しました。
3.原因
CStringはMFCと共に使用することを前提に作られているので通常のコンソールアプリケーションの設定では使えないらしい。
4.解決方法
始めからMFCプログラムとして作成しないと使用できない模様。CStirng.hが読み込めない
5.Link
掲示板1
掲示板2

if文の条件文部分の書き方が安全ではない

1.ErrorMessage
warning C4804: '<' : 演算中の 'bool' 型の使用方法が安全ではありません
2.現象
if文の条件文部分で'<'演算子を多用したところ上記の警告が出た。
3.原因
if( 190 <  x < 610)
のような書き方をしてしまった。
4.解決方法
if( ( 190 < x ) && ( x < 610 ) )
と書きなおすべし。
5.Link
ほぼ同じ警告例

Debugフォルダ内のexeファイルが起動しない

1.現象
デベロッパースタジオの「デバッグなしで開始」からは実行できるがDebugフォルダ内のexeファイルからでは実行できない。
2.ErrorMessageDialog

OpenCV GUI Error Handler

Bad argument (Array should be CvMat or IplImage)
in function cvGetSize, C:\User\VP\opencv\cxcore\src\cxarray.cpp(1453)
Press "Abort" to terminate application.
Press "Retry" to debug (if the app is running under debugger).
Press "Ignore" to continue (this is not safe).

中止(A) 再試行(R) 無視(I)

3.原因
プログラム内で使用する画像がDebugフォルダになかった。デベロッパースタジオからの起動とDebugフォルダからの起動では画像フォルダのパスがそれぞれ異なっていた。
4.解決方法
Debugフォルダ内に必要な画像を用意する。
5.教訓
そもそもBad argumentのエラーダイアログでは原因がわからないので画像がない場合のエラー処理を考えておくべきだった。

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2009年01月20日 13:54
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。