3

多くの若いプログラマーと同じように、コードのさまざまなポイントに「here1」、「here2」などの多数の print-to-console ステートメントを挿入して、プログラムがいつうまくいかないかを把握することの有用性を学びました。このブルート フォース デバッグ手法は、CS の研究を通じて何度も私を救ってくれました。しかし、C でプログラミングを始めたとき、興味深い問題に出くわしました。走ってみたら

void* test;

printf("hello world");
test[5] = 234;

もちろん、testCharのメモリをmallocしていないため、セグメンテーション違反が発生します。ただし、それがコードの流れであるため、セグフォルトが発生する前に「hello world」が出力されると論理的に考えるでしょうが、私の経験では、セグフォルトが最初に発生し、「hello world」が常に発生する場合があります。 " がコンソールに出力されることはありません。(この正確な例をテストすることはできませんでしたが、Linuxボックスでgccを使用してこの種の状況に何度も遭遇しました。)これは、コンパイラがいくつかのものを再配置したり、printfを実行したりすることに関係していると推測しています非同期的にフラッシュされるため、即時ではないある種のバッファを使用します。正直なところ、なぜそうなるのかはわからないので、これは完全に私の推測です。私が使用した他の言語では、「testChar = ...

私の質問は、C をプログラミングしているときになぜこれが起こるのですか? hello world が最初に出力されないのはなぜですか? 次に、同じ基本的なことを達成するこれよりも優れた C プログラミングのデバッグ手法はありますか? のように、問題のあるコード行を見つけるための簡単で直感的な方法は?

編集:私は偶然に実際の例を挙げました。私が今持っているものは、セグメンテーション違反を引き起こすはずです。おもしろいことに、セグメンテーション違反が必要ないときは通常、セグメンテーション違反を取得しますが、実際にセグメンテーション違反が必要な場合は、正当なコードを記述します!

4

7 に答える 7

10

あなたが投稿したコードは完全に合法であり、セグメンテーション違反を引き起こすべきではありません.mallocする必要はありません. あなたの問題は別の場所にあるはずです - 問題の原因となるコードの最小の例を投稿してください。

編集:コードを編集して、まったく異なる意味を持つようにしました。それでも「hello world」が表示されないのは、出力バッファがフラッシュされていないためです。追加してみる

fflush( stdout );

printfの後。

問題の原因を突き止めるには、いくつかの選択肢があります。

  • __FILE__および__LINE__C マクロを使用して、コード全体に printfs を散りばめます。
  • デバッガーの使い方を学ぶ - プラットフォームがコア ダンプをサポートしている場合は、コア イメージを使用してエラーの場所を見つけることができます。
于 2009-06-10T13:09:54.657 に答える
5

printfバッファリングされる stdout に書き込みます。プログラムがクラッシュする前にそのバッファがフラッシュされないことがあるため、出力が表示されません。これを回避するには、次の 2 つの方法があります。

  1. fprintf( stderr, "error string" );stderr はバッファリングされないため、使用します。
  2. fflush( stdout );printf 呼び出しの後にへの呼び出しを追加します。

ニールと他の人が言ったように、書かれたコードは問題ありません。つまり、testChar指しているバッファーの変更を開始するまでです。

于 2009-06-10T13:12:47.803 に答える
5

「問題のあるコード行を見つけるための簡単で直感的な方法はありますか?」

gdb (またはその他のデバッガー) を使用します。

プログラムのセグメント エラーの場所を見つけるには、-gオプションを指定してコンパイルし (デバッグ シンボルを含める)、gdbからアプリケーションを実行します。セグメント エラーで停止します。

次に、btコマンドを使用してバックトレースを調べて、どの時点でセグ フォールトが発生したかを確認できます。

例:

> gdb ./x
(gdb) r
Starting program: /proj/cpp/arr/x 
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x000019a9 in willfail () at main.cpp:22
22          *a = 3;
(gdb) bt
#0  0x000019a9 in willfail () at main.cpp:22
#1  0x00001e32 in main () at main.cpp:49
(gdb) 
于 2009-06-10T13:14:04.493 に答える
3

出力はデフォルトでバッファリングされ、出力が実際に stdout に書き込まれる前に segfault が発生します。試す:

fprintf(stderr, "hello, world\n");

(stderr はデフォルトではバッファリングされません。)

于 2009-06-10T13:14:01.903 に答える
1

このコードはセグメンテーション フォールトしないはずです。リテラル文字列へのポインターをポインター変数に代入しているだけです。strcpyたとえば、無効なポインターを使用してコピーする場合は、状況が異なります。

メッセージが表示されないのは、バッファリングされた I/O が原因である可能性があります。改行文字を出力するか、出力バッファーをフラッシュする\n呼び出しを行います。fflush

于 2009-06-10T13:11:50.427 に答える
0

2 つの問題があります。1 つ目は、(元の) コードがセグメンテーション フォールトしないことです。その文字列定数を char ポインターに割り当てることは完全に有効です。しかし、今はそれを脇に置いて、セグメンテーション違反になる何かをそこに置いたふりをしましょう。

次に、通常は C ランタイム ライブラリのバッファと OS 自体のバッファの問題です。それらをフラッシュする必要があります。

これを行う最も簡単な方法は次のとおりです (UNIX では、Linux では完全に確実ではありませんfsyncが、システム自体がダウンしない限り、これが最終的に発生することを保証する必要があります)。

printf ("DEBUG point 72\n"); fflush (stdout); fsync (fileno (stdout));

私はこれを UNIX で頻繁に実行しており、C ランタイム ライブラリが UNIX にフラッシュされ ( fflush)、UNIX バッファがディスクに同期される ( ) ことが保証されfsyncます。別のファイル ハンドル。

于 2009-06-10T13:12:47.333 に答える
0
void* test;

printf("hello world");
test[5] = 234;

「hello world」がシステムのどこかにバッファリングされており、すぐに画面に出力されない可能性があります。プロセス/スレッド/画面書き込みを担当するものは何でも、それを処理する機会を得ることができるのを待って保存されます。そして、待機中 (および出力する他のデータをバッファリングしている可能性があります) に、関数は終了しています。不正アクセスやセグメンテーション違反を乗り越えます。

于 2009-06-10T13:17:00.307 に答える