C言語の見えないバグ、対処法でも語るスレ

このエントリーをはてなブックマークに追加
C言語使っていて予期せぬバグ、またそれの対処法やtipsでも語りましょう。

質問は質問スレへどぞー
ttp://pc2.2ch.net/test/read.cgi/tech/1064234533/l50
バイナリファイルを開くときにモードを"rb"ではなく"r"にしてしまい、気づくのに結構時間がかかった。
まあ default のタイポ・・・ カラードエディタ使ってない頃はよくやった。
数年前にfjかどっかで、exitの前にfreeが必要かって、延々やってたんですけど、
あれ結局結論はどうなったんですか?
>>4
1年以上やってたのは知ってるが、結論は・・・
>>5
僕も途中で飽きて読むの止めちゃったんですよねぇ・・・
馬鹿はほっとくしかないよな。
free しなくてもシステムが開放してくれるから大丈夫
ってのが納得出来ない人がいて、延々と同じ話題を繰り返していたような・・

あの頃はもう fj ほとんど読まなくなってたんだけどね
9デフォルトの名無しさん:03/09/25 23:27
入力方法を標準入力かファイル入力かif文で分けて
ファイル入力の場合は入力ファイルをオープンするわけです。
そのあと検索ファイルを開いて文字列を検索し
その結果を出力ファイルを開いてファイルに出力。
で、その後最後にfclose()を行うわけだが
ここで一気に入力、検索、出力のファイルをクローズしてしまっていた為
標準入力の場合はオープンしてないファイルをクローズする命令になっていた。
実行結果としては
ファイル入力→出力…○
標準入力  →出力…×
となっていた。
その構造に気づかずに、標準入力とファイル出力は相性が悪いのかなぁ…
と勝手に思っていたDQNでした。
>>8
あげくのはてに、exitをreturnに変えて再利用したとき、
リークするからとかなんとか・・・
これ系を活用するとか??
#if defined(_Debug)
#define DStr(S) puts(S)/*putsは他に置き換えできる。*/
#else
#define DStr(S)
#endif

VC使ってるけど、デバッグの時はありえない値をバカスカ入れて、ウオッチしてるよ。
ブレークポイントをしっかり設定してやばげなら中止する。
基本的に配列などは最初と最後と大体の中間だけ見てるけどこういうのはヤバイかな??
メモリリークが問題になるようなアプリケーションでは、すべてをfree(あるいはdelete)しておいて、
Purifyなどのメモリリークチェッカを使ったほうが、リークのチェックをしやすい。
>>11
初心者がよくそういうのを使うね。
DStr()をそういう小手先のマクロにするんじゃなくて、
ちゃんとデバグ用関数として作るほうがいいと思う

>>12
fj の件なら、メモリリークはアプリじゃなくて、システム(OSとか)で
起きるかもしれない、というのが論点だった。
たとえば、Windows アプリを強制終了すると、資源がリザーブ
されたままになっちゃうとか、そういう話。
>>9
> 入力方法を標準入力かファイル入力かif文で分けて

何のために、標準入力とファイル入力が同じファイル識別子が使えるようになっているのか...。
単につくりがしょぼいだけのことだろ。
>>13
>DStr()をそういう小手先のマクロにするんじゃなくて、
>ちゃんとデバグ用関数として作るほうがいいと思う

たとえばどんなの?
>>15
ttp://www.pro.or.jp/~fuji/
Cプログラミング診断室にマクロうんぬんあったんで行ってみれば?
1713:03/10/04 20:22
>>15
どんな関数であるかはあまり重要でない。
マクロで作るというのは、デバグが終わったら消しちゃえ、ぐらいに
軽視していると思う。

と述べた上で、デバグ関数には次のような機能があるとよいかと。

 ・スイッチで出力のオンオフが出来る
 ・スイッチでレベルの変更が出来る(-vオプションとか)
 ・出力先を選択、ファイルならラップするとか
 ・時刻などの必須パラメタを埋め込む、出力形式を揃える、などなど

ついでに、マクロ定数の有無で存在ごと消えてくれればよりいいね。
19デフォルトの名無しさん:03/10/05 08:14
どうかな?
マクロ定数で存在が消えたら実行ファイルが小さくなるというのはメリットかもしれないけど
CPUリソースが豊富になった今ではそれほどの価値はないでしょ。
そりゃ、組み込みで本番ではテスト環境の容量半分で、とかなら別だけどさ
>12
fclose()の話と続いたので気になったんだけど、
double free とかのトラブルは無いの?
2112:03/10/06 12:56
>>20
うーん、質問の趣旨が良くわかりませんが、問題は無いと思います。
>>exit前のfree
プログラマがクリエートした資源を捨てるのはプログラマ責任でやるべき
だろう。allocしたならfreeするのは議論すべきまでもない気がするが・・・。
(プロセス内の事はプロセス内で片づけろ、という事)

>>テスト用の関数
ウチの会社では、Cで開発する場合、関数毎にダミーのmainを付けて、単体
テストを終えてから、mainを取り外して内部出荷していた。
さらに、関数内部には、入り口と全ての出口に、内部変数の表示マクロが
あり、異常ルートにも表示マクロがあった。これらは「プログラマの想定外
の値だったら、表示する」というマクロだった。
しかも最終出荷まで生きているマクロだった(つまり、試験期間中はずっと
生きている)。
このまま試験すると、バグがある時は大量の変数表示が出るわけだが、大量
と言っても実行ログはテキストファイルであり、たかが知れた量。
grepとかで異常を検出すれば良いだけの話。
最初、「いちいち関数毎にマクロ埋めるのめんどくせー」とか思っていたが、
大規模開発の時には、その恩恵にあずかったよ。
そうだね。組み込みだと、実機に組み込む前に出来るだけ試験しておきたいから
そういうのは普通にやるよね。
24デフォルトの名無しさん:03/10/18 13:08
age
25デフォルトの名無しさん:03/10/20 20:28
見るんじゃなくて感じるものだと思うyp
Use the forse everybody.
Use the horse?
2826:03/10/22 11:51
×forse
○force

鬱氏・・・
29デフォルトの名無しさん:03/10/26 12:50
signed - unsigned = unsigned になるのはわりと注意しているが
signed/unsigned = unsigned になるのは盲点だった・・・
unsigned char
signed char
char
がそれぞれ別の型なのはC++だけだっけ?
C だと char が unsigned char か signed char のどちらかと同じになる。
どちらと正しいかは処理系定義。

C++ だと>>30のいうとおりにそれぞれ別の型だな。
keil社のCコンパイラで、~1も~0もどちらも1になった。1bitのポート出力の所で、
#define ACT 1 として PORT=ACT; も PORT=~ACT; も どちらも BCLR PORT が出ず
BSET PORT が出た。仕方なくPORT=1^ACT; と書いて0を出させた。
当然だけどscanf("%d", n);のときに数字以外が入力されたら……。
>>19
アクションゲームとか作るんだよ!
デバッグコードが入ってるとPen133MHz対応が微妙になるんだよ!
35デフォルトの名無しさん:04/10/15 17:44:19
http://pc5.2ch.net/test/read.cgi/prog/1087570224/506
> sizeof(配列名)とsizeof(&配列名[0])って両方とも要素のサイズじゃなくて
> 配列全体のサイズになんのな。以前ハマタ。

sizeof(&配列名[0])は知らなかった。
36デフォルトの名無しさん:04/10/15 17:50:34
>>35
コンパイラが腐ってるだけじゃねーの?
3735:04/10/15 22:48:57
>>36
今試してみたらどうもそうらしい。
さっき試したときはこんなコード。(コンパイラはBCC)
char test[4];
printf("%d", sizeof &test[0]);
よくよく考えたらsizeof (char *)も4だった。OTL
今いろいろと要素数を変えてみても結果は4のまま。

やっぱりそこの506の使っていたコンパイラに問題ありのようだ。
38デフォルトの名無しさん:04/10/16 02:09:03
case 書き忘れてるんだけど、後継 xxx: がラベルに解釈されてて
戸惑う事が年に1度はある。

見えるバグだけど、書き忘れなだけに見えないバグとも言える。
39デフォルトの名無しさん:04/10/16 13:09:33
default: の綴り間違った時は悲しいよね
40 ◆OaTCP/IPW6 :04/12/07 21:42:26
aaa
41デフォルトの名無しさん:04/12/11 23:28:46
>>39
キーワードに色がつくエディタ使いなよ。
って2ヶ月前の書き込みか orz
42デフォルトの名無しさん:04/12/14 20:08:45
というかラベル使ったらwarning出るようにしてほしい。
43デフォルトの名無しさん:05/01/06 23:46:17
register変数はアドレス演算子でアドレスを取ることもできないが、
配列→ポインタの暗黙の変換もできなくなるので、
配列にregister指定するとその変数にはなんとsizeof以外、何もできなくなるそうな。

当たり前に思っていることがちょっと集まっただけで信じられないことが起こるもんだ。
44デフォルトの名無しさん:05/01/07 09:06:10
>43
環境による。
45デフォルトの名無しさん:05/01/07 09:10:53
>>44
そうは言っても規格を厳密に解釈するとそうなるわけで。
46デフォルトの名無しさん:05/02/15 04:12:21
出来るだけポータブルに書こうとすると避けて通れないわけで。
47デフォルトの名無しさん:05/02/15 10:09:08
case文でbreakを忘れて酷い目にあった。
48デフォルトの名無しさん:05/02/15 12:20:24
>>47
祈りなさい。
じゃなかった。
case/defaultの':'を書いたらすぐにbreak;を書く癖をつけてみるとか。
thruしたいロジックなんてめったに無いだろうからそれで充分。
switch () {...}の最後にbreak;がくるのが気に入らないならご愁傷様で。
49デフォルトの名無しさん:05/02/16 15:47:46
break書かないときにwarningくらい出してほしいもんだな。
50デフォルトの名無しさん:05/02/16 21:02:07
つ[lint]
51デフォルトの名無しさん:05/02/17 12:19:50
>>49
switch (foo) {
case 0: /* こことか */
case 1:
return; /* こことか */
default:
...; /* ここで */
} /* いちいち警告出たら鬱陶しい。 */
52デフォルトの名無しさん:05/03/03 01:42:18
goto使うようにすれば解決。

static void *code[] = {&&L1,&&L2, &&L3, ... &&Ln};
void**pc = code;
goto *pc++;

L1:
goto *pc++;
L2:
goto *pc++;
L3:
goto *pc++;

Ln:
goto *pc++;

VCで使えるようになればなあ・・
53デフォルトの名無しさん:05/03/19 17:31:20
番兵法ってなんですか?
54デフォルトの名無しさん:05/03/19 18:33:24
>>53
配列もしくはそれに準じるデータ構造において、末尾要素に値域外の値を格納しておき、
反復処理時に終了判定を簡潔にする方法
55デフォルトの名無しさん:05/03/19 21:23:28
>>52
今の時代goto使ってる輩なんてアホ丸出し
56デフォルトの名無しさん:05/03/20 02:32:45
>>55
時代に無関係にgoto使う人間は使うのだよ
57デフォルトの名無しさん:2005/03/21(月) 12:54:47
C言語のヒープメモリの管理どうしてる?
おれはこういうの作ってるけど。

f() { //適当な関数
mem_t mem = memalloc(); //適当に確保したメモリ
handle_t handle = protect_attach(mem, memfree); // メモリを保護対象にする


//この区間でエラーが起きてもOK


mem = protect_detach(handle); // メモリ保護を解除する
memfree(mem); //メモリを開放
}


error_recv() { //エラー復帰処理
protect_rewind(); // ここでメモリを全て開放する
}


handle = protect_block(); // ブロックを保護対象にする
protect_attach(memalloc(), memfree);
protect_attach(memalloc(), memfree);


protect_rewind_block(handle);
でブロック単位で一気に開放したり。
58デフォルトの名無しさん:2005/03/21(月) 13:00:53
時代がどうとかで判断する >>55 が阿呆なのは
異論がないところだろうが、それはそれとしても >>52
使い方は上を行く阿呆。
59デフォルトの名無しさん:2005/03/21(月) 13:10:37
>>58
VMの実装とかではおなじみな手法だけど。
60デフォルトの名無しさん:2005/03/22(火) 20:17:46
>>59
阿呆ばっかりなのか。
61デフォルトの名無しさん:皇紀2665/04/01(金) 02:12:50
>>47
どこかで見かけたマクロ。
#define Case break; case
#define Default break; default

俺は真似したくないが…
62デフォルトの名無しさん:皇紀2665/04/01(金) 09:06:50
>>61
ダメすぎマクロの典型だなぁ。
そのマクロを使うことで、その技術者はどんどんダメになっていくという…
63デフォルトの名無しさん:int 2ch =05/04/02(土) 11:00:45
>>61
結城浩とか、そのシンパが使いそうだな
64デフォルトの名無しさん:2005/04/20(水) 13:51:53
#define CASE_EXEC(caseVal, func)case(caseVal):{func; break;}
みたいなのを作って、

switch(caseVal) {
  CASE_EXEC(1, func1());
  CASE_EXEC(2, func2());
}
こんなのはどうだろう。
65デフォルトの名無しさん:2005/04/20(水) 14:03:09
>>64
どうだろうって、ダメダメに決まってるじゃないか。
66デフォルトの名無しさん:2005/04/20(水) 18:59:52
>>64
Windowsのメッセージクラッカがそんなことをやっている。
WindowsX.hのHANDLE_MSGマクロがそう。
メッセージごとに関数の引数を変えられるよう、さらにHANDLE_WM_〜ってマクロを呼ぶようになっているが。
67デフォルトの名無しさん:2005/04/20(水) 21:03:19
>>66
windowsx.h のマクロは SelectBitmap とか結構使ってるけど
メッセージクラッカは使ってないな。
どうもしっくりこなくて。
68デフォルトの名無しさん:2005/04/20(水) 21:18:45
逆に俺はSelectBitmapの類いを使ったことは全然無いな。
69デフォルトの名無しさん:2005/04/21(木) 12:25:55
マクロは便利だけど、マクロ使いすぎるとソース引き継ぎにくくなるな。
70デフォルトの名無しさん:2005/04/22(金) 23:44:34
お前が会社と心中するつもりならそもそも引き継ぐなんて事態は発生しないから
大丈夫!
71デフォルトの名無しさん:2005/12/17(土) 06:10:29
ここかな。
72デフォルトの名無しさん:2005/12/17(土) 17:43:59
おまえら、観測不能なバグはバグじゃない。
これがプログラミングの正義だ。そうだな?

これまでにもハッカーは幾度となくprintfを改良し続け
ついにgccはコンパイル時にフォーマット引数を解析するまでに至った。
20世紀も末の事だ。
その日からだ。俺らは、街中で「lisp makes love'n'piece!」と叫んでも
なんら恥ずかしくは無くなった。

この成長は何によるものか?
愛があったからだ。
決してベラルーシの放射能混じりの、質の悪い "ベヴンズ・ブルー" のおかげでは /無い/。
# 新橋のイラン人め、妙なモノを売りつけやがって!告訴してやる!

そしたら、分かるだろ?
もうバッファがあふれるとかあふれないとか、そういう問題じゃない。な?
ゼロ除算は萌え。な?

バグは見えるもんじゃない。「魅せる」もんだって事だ。
73デフォルトの名無しさん:2005/12/20(火) 03:24:22
愛だのなんだの、そんなこと言っても所詮は人間、
金が絡むと責任問題に発展するわ仕舞いにゃ人死にも出る
そのプログラム上でどれだけの金が動くか、
バグ1つにどれだけ金の重みが加わるか、
所詮それだけよ
74デフォルトの名無しさん:2006/01/23(月) 16:03:43
segmentation とかの実行時エラー出されると、マジで嫌になる。
どっかでバッファオーバーフローしてるのを探すのは非常に大変。
入力するデータによってはバッファオーバーフローしてても正常な
出力が得られる場合もあって、これで見逃したりして非常に嫌だ。
漏れはこのせいで一日中デバッグにあたったことがある。
75デフォルトの名無しさん:2006/01/23(月) 19:02:45
たかだか、一日中でそんなこというな。
76デフォルトの名無しさん:2006/05/27(土) 01:42:25
プログラム作業は99%のバグ取りと、1%のアルゴリズム考案で出来ている
77デフォルトの名無しさん:2006/06/07(水) 23:12:58
その手のバグを半年くらい様々に手をつくして対処したことがあったなあ。
ユーザーにもアミとか出して迷惑かけた。
78デフォルトの名無しさん:2006/07/24(月) 20:59:54
     /\___/ヽ
   /    ::::::::::::::::\
  . |  ,,-‐‐   ‐ -、 .:::|
  |  、_(・)_,:  _(・)_, :::|
.   |    ::<      .::|
   \  / −  ヽ ::/
   /`ー‐--‐‐―´\
79デフォルトの名無しさん:2006/08/22(火) 00:08:57
つい最近やっちまったこと。

とある関数内で、変数の名前を変えることにした。なお、その関数は10行もない。
だが、1箇所変数の名前を変え忘れていた。実は元の変数名はとあるグローバル変数にも使われていた。
そのためエラーにならずコンパイルできてしまい……。

書いてから思った、Cでなくても同じことやらかすことはできるなと。
以上チラシの裏。
80デフォルトの名無しさん:2006/08/22(火) 02:20:26
まぁ、名前のぶつかりやすい一文字変数を避けようってこった。
まして、グローバル変数には意図的に長い名前をつけるくらいで丁度いい。
81デフォルトの名無しさん:2006/09/26(火) 09:16:36
chk
82縺ク縺ェ縺。繧?縺? ◆krMXIQvIwY :2006/09/26(火) 09:20:34
test
83へなちょこ ◆krMXIQvIwY :2006/09/26(火) 09:27:44
test
84へなちょこ ◆Rhvbchu7bg :2006/09/26(火) 12:04:38
test2
85へなちょこ ◆krMXIQvIwY :2006/09/26(火) 19:27:17
>1
>11
>>111
86デフォルトの名無しさん:2006/09/27(水) 06:10:44
test1
87デフォルトの名無しさん:2006/10/12(木) 13:17:06
何でスレが取得できないのでしょうか?
88デフォルトの名無しさん:2006/10/13(金) 09:39:02
落ちそうなスレだけど、質問させて 下のコード、コンパイル出来るけど、
実行出来ません。誰かどうしてか教えて

#include<stdio.h>
#include<stdlib.h>

void initialize(int i,int j,int L,int grid[][L]); //initializes all the grids to zero.


main()
{
int L,p;
int i,j;
int grid[L][L];
printf("linear size of the square lattice L:->");
scanf("%d",&L);
printf("occupation probability p:->");
scanf("%f",&p);
initialize(i,j,L,grid);


}

void initialize(int i,int j,int L,int grid[][L]){
for(i=0;i<L;i++){
for(j=0;j<L;j++){
grid[i][j]=0;
}
}
return;
}
89デフォルトの名無しさん:2006/10/13(金) 10:30:23
vc++EEでビルドしてみろ
90デフォルトの名無しさん:2006/10/13(金) 10:55:28
>>88
>コンパイル出来るけど
またまたご冗談を (AA略
91デフォルトの名無しさん:2006/10/13(金) 20:20:23
リンクするの忘れてるんじゃね?
92デフォルトの名無しさん:2006/10/13(金) 23:45:42
スッゴイ簡単なプログラムなんで申し訳ないのだが教えてください。以下のプログラムを実行すると
http://i-bbs.sijex.net/imageDisp.jsp?id=test&file=1160750139347o.jpg
この画像の黒い画面の一番右下のように表示されてしまいます

整数A:0
整数B:1
整数C:2
で0を出力させたいんだがわけのわかんない数字(ここでいうと整数Aは0の前の2、Bは1の前の2280676など)
が出てしまいます。しかもコノ場合0ではなく1が出力されてしまいます。
原因不明なのでどうか教えていただけないでしょうか?

#include <stdio.h>
int main (void){

int x,y,z;
int min; /*minは最小値*/

printf("3つの整数を入力してください。");
printf("整数A:%d");scanf("%d",&x);
printf("整数B:%d");scanf("%d",&y);
printf("整数C:%d");scanf("%d",&z);

min = z;
if (x < z) min = x;
if (y < z) min = y;

printf("最小値は%dです。\n",min);

return(0);
}
93デフォルトの名無しさん:2006/10/13(金) 23:53:36
printfの使い方が間違ってる。
最小値の求め方も間違ってる。
あと>>1読め。

#include <stdio.h>
int main (void){

int x,y,z;
int min; /*minは最小値*/

printf("3つの整数を入力してください。");
printf("整数A");scanf("%d",&x);
printf("整数B");scanf("%d",&y);
printf("整数C");scanf("%d",&z);

min = z;
if (x < min) min = x;
if (y < min) min = y;

printf("最小値は%dです。\n",min);

return(0);
}
94デフォルトの名無しさん:2006/10/13(金) 23:59:49
>>93
スレ違いごめんなさい。あとすぐ教えてくれて有難う御座います!
いつもprintfの使い方が違ったからバグってたのか・・・。
使い方もちょっとおかしかったですねorz

これからは注意深くいきていきます

まじ感謝です!
95デフォルトの名無しさん
>91
リンク以前に(狭義の)コンパイルができない