exit,_exit,returnの違い

3568 ワード

exitと_exitの2つの関数には一定の違いがあり、場合によっては混用できないことがあります.まずexitがglibc-2.16にあることを見てみましょう.0の定義は何ですか?
void
exit (int status)
{
  __run_exit_handlers (status, &__exit_funcs, true);
}
それは呼び出しによってrun_exit_handlersの関数で実現されます.では_run_exit_handlersはどうやって実現したのでしょうか.
DEFINE_HOOK (__libc_atexit, (void))


/* Call all functions registered with `atexit' and `on_exit',
   in the reverse of the order in which they were registered
   perform stdio cleanup, and terminate program execution with STATUS.  */
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
		     bool run_list_atexit)
{
  /* We do it this way to handle recursive calls to exit () made by
     the functions registered with `atexit' and `on_exit'. We call
     everyone on the list and use the status value in the last
     exit (). */
  while (*listp != NULL)
    {
      struct exit_function_list *cur = *listp;

      while (cur->idx > 0)
	{
	  const struct exit_function *const f =
	    &cur->fns[--cur->idx];
	  switch (f->flavor)
	    {
	      void (*atfct) (void);
	      void (*onfct) (int status, void *arg);
	      void (*cxafct) (void *arg, int status);

	    case ef_free:
	    case ef_us:
	      break;
	    case ef_on:
	      onfct = f->func.on.fn;
#ifdef PTR_DEMANGLE
	      PTR_DEMANGLE (onfct);
#endif
	      onfct (status, f->func.on.arg);
	      break;
	    case ef_at:
	      atfct = f->func.at;
#ifdef PTR_DEMANGLE
	      PTR_DEMANGLE (atfct);
#endif
	      atfct ();
	      break;
	    case ef_cxa:
	      cxafct = f->func.cxa.fn;
#ifdef PTR_DEMANGLE
	      PTR_DEMANGLE (cxafct);
#endif
	      cxafct (f->func.cxa.arg, status);
	      break;
	    }
	}

      *listp = cur->next;
      if (*listp != NULL)
	/* Don't free the last element in the chain, this is the statically
	   allocate element.  */
	free (cur);
    }

  if (run_list_atexit)
    RUN_HOOK (__libc_atexit, ());

  _exit (status);
}

長いセグメントのコードで、他の関数も引用されています.私たちはしばらく構いません.まず、関数のコメント・セグメントを見てみましょう.
/* Call all functions registered with `atexit' and `on_exit',
   in the reverse of the order in which they were registered
   perform stdio cleanup, and terminate program execution with STATUS.  */

すなわち、この関数の最初の再帰的な呼び出しはatexitまたはon_によって行われる.exitに登録された関数は、入出力ストリームを空にし、最後に呼び出されます.exitはプロセスを終了します.これで分かりますexitは正しいですexitによるパッケージ、exitの前に他の操作があります.に至ってはexit関数のソースコードを検索しています.exitには多くのバージョンが登場しています.exitですが、具体的にどのように呼び出すかはよくわかりません.どうせexitが正しいことを知っておく必要があります.exitはパッケージ化されていますが、彼らは同等ではありません.
彼らの違いはどのような影響を及ぼすのでしょうか.あるいは彼らの間に何か使うときに注意しなければならないところがありますか?ここでは他の人のまとめを引用して、以下のようにします.
‘exit()’と‘_exit()’の基本的な違いは、前の呼び出しがライブラリ内のユーザ状態構造(user-mode constructs)を実装することに関連するクリーンアップ作業(clean-up)であり、ユーザがカスタマイズしたクリーンアッププログラム(注:カスタムクリーンアッププログラムはatexit関数によって定義され、何度も定義され、逆順序で実行される)を呼び出すことに対応し、後の関数はプロセスのためにカーネルクリーンアップ作業のみを実装することである. 
「fork()」によって作成されたサブプロセスブランチでは、標準入出力(stdio:Standard Input Output)のバッファが2回空になるため、通常は「exit()」を使用するのは正しくありません.また、テンポラリファイルは予想外に削除されます(テンポラリファイルはtmpfile関数によってシステムテンポラリディレクトリに作成され、ファイル名はシステムによってランダムに生成されます).静的ターゲット(static objects)の構造関数(destructors)が誤って実行できるため、C++プログラムでは状況がさらに悪化する.(デーモンなど、親プロセスが子プロセスではなく'_exit()を呼び出す必要がある場合もあります.ほとんどの場合に適用される基本ルールは、「exit()」が「main」関数に入るたびに呼び出されることです. 
「vfork()」によって作成されたサブプロセスブランチでは、親プロセスの状態に影響を与えるため、「exit()」の使用はさらに危険になります.
returnとexitの違いについては、returnは言語レベルであり、プログラミング言語のキーワードであり、呼び出しスタックの戻りを表す.exitはシステムレベルであり、プロセスの終了を表します.ではなぜmain関数はreturnだけで終わるのでしょうか.それはmainがexit関数を暗黙的に呼び出したからです.