2

このサイトで提供されている sudo のソース コードを閲覧していたところ、メインのこの非常に奇妙な型シグネチャ (ボーナスの質問: 「型シグネチャ」を表す C に似た用語はありますか?) に出くわしました。

int
main(argc, argv, envp)
    int argc;
    char **argv;
    char **envp;
{

スタイル自体がオールドスクールK&Rなのが分かります。私が本当に興味を持っているのは、 main がボーナス引数 を取っているという事実ですchar **envp。なんで?sudo はかなり標準的なコマンド ライン ツールであり、そのように呼び出されます。オペレーティング システムは、通常の関数で定義されていない main 関数に遭遇したときに何をすべきかをどのように認識しますか?(int argc, char *argv[])?

多くの場合、私自身は怠け者であり、引数を完全に省略しており、私が書いているプログラムはどれも問題なく動作するように見えます (C で発生する可能性がある最も危険なこと、私は知っています :p)

私の質問のもう 1 つの部分は、これによりどのような優れたことが可能になるかということです。組み込みプログラミングのヒープに役立つ予感がありますが、悲しいことに、それへの露出は最小限であり、実際には言えません。具体例をいくつか見てみたい

4

2 に答える 2

1

http://en.wikipedia.org/wiki/Main_function

最初の段落から:

他のプラットフォーム依存の形式も C および C++ 標準で許可されていますが、C++ では戻り値の型は常に int でなければなりません;[3] たとえば、Unix (ただし POSIX.1 ではありません) と Microsoft Windows には、プログラムの環境。それ以外の場合は、stdlib.h の getenv を介してアクセスできます。

グーグルはあなたの友達です。また、この場合、オペレーティング システムはメインについて何も知る必要はありません。作業を行うのはコンパイラであり、コンパイラによって受け入れられる有効な引数である限り、問題はありません。

于 2013-06-02T22:20:24.690 に答える
1

これは、環境への単なるポインターであり、

extern char **environ;

どちらもバージョン 7 以降の UNIX で使用できます (バージョン 6 には環境変数がありませんでした)。名前が標準化externされました。environdont の 3 番目の引数mainmainある種のファッション ステートメントを除いて、3 引数を使用する理由はありません。

呼び出すプロセス セットアップ コードは、mainmain が 3 つの引数を予期するかどうかを知る必要はありません。アセンブリ レベルでは、2 つの引数を受け取る関数と 3 つの引数を受け取るが 3 つ目の引数を使用しない関数の間に違いはないからです。または、引数を取らない関数と 2 つの引数を取り、それらを使用しない関数の間でも機能しますint main(void)

Unix に似ていない ABI を使用するシステムでは、どの種類の ABI をmain呼び出しているかを知る必要がある場合があります。

これを 1 つのファイルに入れます。

#include <stdio.h>

int foo(int argc, char **argv)
{
  int i;
  for(i=0;i<argc;++i)
    puts(argv[i]);
  return 0;
}

そして、これは別のものです:

extern int foo(int argc, char **argv, char **envp);
int main(int argc, char **argv)
{
  char *foo_args[] = { "foo", "arg", "another arg" };
  char *foo_env[] = { "VAR=val", "VAR2=val2" };
  foo(3, foo_args, foo_env);
  return 0;
}

これは、クロスプラットフォームの言語弁護士の観点からは完全に間違っています。の型についてコンパイラに嘘をつき、foo必要以上の引数を渡しました。しかし、UNIXでは機能します。余分な引数は、関数が戻った後に呼び出し元によって適切に考慮されてクリーンアップされるスタック上のスロットを無害に占有するか、呼び出し先が特に何も見つけることを期待していないレジスタに一時的に存在し、呼び出し元が呼び出し先が上書きすることを期待しているため、呼び出し先でレジスタが別の目的で再利用されてもかまいません。

これはまさに、envp引数が 2 つの main を持つ通常の C プログラムで起こることです。argcと をargv使用したプログラムで何が起こるかint main(void)

しかし、envpそれ自体と同様に、これを本格的なコードで利用する正当な理由はありません。型チェックはあなたにとって良いことであり、それを回避できることを知っていることは、そうすべきではないことを知っていることと一緒に行くべきです。

于 2013-06-02T22:59:58.073 に答える