1

次の C プログラムを考えてみましょう。

int main()
{
    waitpid(1337);
}

予想通り、gcc と clang はどちらも waitpid の暗黙の宣言について警告しますが、結果のバイナリは正常に動作します。するとltrace、それがわかります

waitpid(1337, 0x7fff86950ec8, -2037051688)

と呼ばれます。ここで 3 つの質問:

  1. 上記の C コードが機能するのはなぜですか? sys/wait.hwaitpid を呼び出せるようにするには、インクルードする必要があります。printfを呼び出して含めない場合も同じことが起こりstdio.hます。出力は機能します。
  2. したがって、gcc はまだ waitpid を呼び出す魔法を行っていますが、引数が 3 つあるにもかかわらず、引数を 1 つしか指定できないのはなぜでしょうか? ltrace複数回呼び出すと、他の 2 つの引数がランダムな値であることがわかりますか? Gcc は 1 つの引数の waitpid と 3 つの引数の waitpid の間で何らかの変換を行いますが、どのように?
  3. 最後の 2 つの引数の背後にある値を把握するために gdb を使用するにはどうすればよいですか? 他の 2 つの値はソースコードに表示されません。gcc でそれらにアクセスするにはどうすればよいですか?

私が集めたいくつかの手がかり: main 関数のアセンブラー出力を調べました。

0x000000000040050c <+0>:    push   %rbp
0x000000000040050d <+1>:    mov    %rsp,%rbp
0x0000000000400510 <+4>:    mov    $0x539,%edi
0x0000000000400515 <+9>:    mov    $0x0,%eax
0x000000000040051a <+14>:   callq  0x4003f0 <waitpid@plt>
0x000000000040051f <+19>:   pop    %rbp
0x0000000000400520 <+20>:   retq   

したがって、正確に1つの引数(1337)を取るwaitpid関数が実際にあるように見えるので、何かを行うのはgccではないと思いますか?

4

2 に答える 2

3

上記の C コードが機能するのはなぜですか?

たまたま「効く」。C では、プロトタイプを指定せずに、つまりヘッダーをインクルードせずに関数を呼び出すことができます。これを行うと、引数の数と型について想定し、それを呼び出そうとします。明らかに、間違った数の引数で関数を呼び出すと、未定義の動作になります。

6.5.2.2-3

呼び出された関数を示す式の型がプロトタイプを含まない場合、各引数に対して整数昇格が実行され、float 型の引数は double に昇格されます。これらは、デフォルト引数プロモーションと呼ばれます。引数の数がパラメーターの数と等しくない場合、動作は未定義です。

3 番目の質問についてですが、あなたが目にしているゴミはスタックに残っているだけだと思います。それが正しいかどうかを調べるには、 の前にブレークポイントを置き、waitpidそこにステップ インして何が渡されるかを確認します。

于 2013-02-25T08:07:31.020 に答える
0

ヘッダー ファイルを ac プログラムに含めることにより、基本的に関数のプロトタイプを提供します。指定されていない場合は、引数の数と引数の型が cnicutar によって指定されたものと見なされます。また、プロトタイプが定義されていない場合、関数の戻り値の型は int であると想定します。

于 2013-02-25T08:19:34.137 に答える