web-dev-qa-db-ja.com

main()のreturnステートメントとexit()

exit()またはmain()returnステートメントを使用する必要がありますか?個人的に私はreturnステートメントを好みます。コードを読んでいるときに他の関数やフロー制御を読んでいるような気がするからです(私の意見では)。 main()関数をリファクタリングしたい場合でも、exit()よりもreturnを持つ方が良い選択のようです。

exit()returnがしない特別なことをしますか?

186
Srikanth

実際には、is違いがありますが、微妙です。 C++にはより多くの影響がありますが、違いは重要です。

main()returnを呼び出すと、ローカルにスコープされたオブジェクトのデストラクタが呼び出されます。 exit()を呼び出すと、ローカルスコープのオブジェクトに対してデストラクタは呼び出されません!それを読み直します。 exit()返さない。それは、私がそれを呼ぶと、「バックジーはない」ことを意味します。その関数で作成したオブジェクトは破棄されません。多くの場合、これには影響はありませんが、ファイルを閉じるような場合もあります(確実にすべてのデータをディスクにフラッシュしますか?)。

exit()を呼び出しても、staticオブジェクトはクリーンアップされることに注意してください。最後に、abort()を使用すると、オブジェクトは破棄されないことに注意してください。つまり、グローバルオブジェクト、静的オブジェクト、およびローカルオブジェクトにはデストラクタが呼び出されません。

リターンよりも終了を優先する場合は注意して進めてください。

http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a

267
FreeMemory

別の違い:exitは標準ライブラリ関数であるため、ヘッダーを含めて標準ライブラリとリンクする必要があります。 (C++で)説明すると、これは有効なプログラムです。

int main() { return 0; }

ただし、exitを使用するには、インクルードが必要です。

#include <stdlib.h>
int main() { exit(EXIT_SUCCESS); }

さらに、これにより、exitからmainを呼び出すと、ゼロを返すのと同じ副作用があるという追加の仮定が追加されます。他の人が指摘したように、これはあなたが構築している実行可能ファイルの種類(つまり、誰がmainを呼び出しているか)に依存します。 Cランタイムを使用するアプリをコーディングしていますか? Mayaプラグイン? Windowsサービス?ドライバー?各ケースでは、exitreturnと同等であるかどうかを調べるための調査が必要です。 本当に意味するexitのときにreturnを使用すると、コードが混乱しやすくなります。 OTOH、あなたが本当に意味があるexitである場合、必ずそれを使用してください。

24
jwfearn

exitを優先する理由が少なくとも1つあります。atexitハンドラーのいずれかがmainの自動ストレージ期間データを参照する場合、またはsetvbufまたはsetbufを使用して標準ストリームの1つに自動ストレージ期間バッファーを割り当てる場合mainからmainから戻ると、未定義の動作が発生しますが、exitの呼び出しは有効です。

別の潜在的な使用法(ただし、通常は玩具プログ​​ラム用に予約されています)は、mainの再帰呼び出しでプログラムを終了することです。

16
R..

Exit()は 'return'がしない特別なことをしますか?

まれなプラットフォーム用の一部のコンパイラでは、exit()は引数をプログラムの終了値に変換しますが、main()からの戻り値は変換せずにホスト環境に直接値を渡すだけです。

これらの場合、標準は同一の動作を必要とします(具体的には、main()からint- compatibleを返すことは、その値でexit()を呼び出すことと同等です。問題は、OSごとに終了値を解釈するための規則が異なることです。多くの(多くの!)システムでは、0は成功を意味し、その他は失敗を意味します。しかし、VMSでは、奇数の値は成功を意味し、偶数の値は失敗を意味します。 main()から0を返した場合、VMSユーザーにはアクセス違反に関する厄介なメッセージが表示されます。実際にはアクセス違反はありませんでした。これは、障害コード0に関連付けられた標準メッセージでした。

その後、ANSIが登場し、exit()に渡すことができる引数としてEXIT_SUCCESSEXIT_FAILUREを祝福しました。標準では、exit(0)exit(EXIT_SUCCESS)と同じように動作する必要があるため、ほとんどの実装ではEXIT_SUCCESS0に定義しています。

したがって、標準では、値0を持っているfailureコードを返す標準的な方法がないため、VMSにバインドされます。

したがって、1990年代初期のVAX/VMS Cコンパイラは、main()からの戻り値を解釈せず、ホスト環境に値を返しました。しかし、exit()を使用した場合、標準が要求することを行います:EXIT_SUCCESS(または0)を成功コードに、EXIT_FAILUREを一般的な失敗コードに変換します。 EXIT_SUCCESSを使用するには、hadexit()に渡しますが、main()から返すことはできません。そのコンパイラのより新しいバージョンがその動作を維持したかどうかはわかりません。

次のように見えるポータブルCプログラム:

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

int main() {
  printf("Hello, World!\n");
  exit(EXIT_SUCCESS);  /* to get good return value to OS */
  /*NOTREACHED*/ /* to silence lint warning */
  return 0;  /* to silence compiler warning */
}

余談:正しく思い出せば、終了値のVMS規則は奇数/偶数よりも微妙です。実際には、下位3ビットのようなものを使用して、重大度レベルをエンコードします。ただし、一般的に言えば、奇数の重大度レベルは成功またはその他の情報を示し、偶数の重大度レベルはエラーを示しました。

5
Adrian McCarthy

I 強く 2番目のR。プログラムが実際に終了する前にmain()の自動ストレージが再利用されないようにするためのexit()の使用に関するコメント。 main()return X;ステートメントは、exit(X);の呼び出しと正確に同等ではありません。なぜなら、main()の動的ストレージは、main()が戻ると消滅するからです。代わりにexit()の呼び出しが行われても消えません。

さらに、CまたはCに似た言語では、returnステートメントは、呼び出し関数で実行が続行されることを読者に強く示唆しますが、呼び出したCスタートアップルーチンをカウントする場合、この実行の継続は通常技術的に真ですあなたのmain()関数、それはあなたがプロセスを終了するつもりであるときに正確にyouが意味するものではありません。

結局、main()を除く他の関数内からプログラムを終了したい場合、mustexit()を呼び出します。 main()でも一貫してそうすることで、コードがより読みやすくなり、コードをリファクタリングするのが誰でも簡単になります。つまり、main()から他の関数​​にコピーされたコードは、shouldであるはずのreturnステートメントがexit()呼び出し。

したがって、これらの点をすべて組み合わせて結論を出すと、少なくともCではreturnステートメントを使用して悪い習慣になりますmain()でプログラムを終了します。

5
Greg A. Woods

main()の標準プロトタイプはreturnを返すと言うので、私は常にintを使用します。

ただし、標準の一部のバージョンではmainの特別な処理が行われ、明示的なreturnステートメントがない場合は0が返されると想定しています。次のコードを考えます:

int foo() {}
int main(int argc, char *argv[]) {}

G ++はfoo()に対してのみ警告を生成し、mainからの欠落した戻りを無視します。

% g++ -Wall -c foo.cc
foo.cc: In function ‘int foo()’:
foo.cc:1: warning: control reaches end of non-void function
5
Alnitak

Cでは、mainから戻ることは、同じ値でexitを呼び出すこととまったく同じです。

C標準 状態のセクション5.1.2.2.3:

メイン関数の戻り値の型がintと互換性のある型である場合、メイン関数への最初の呼び出しからの戻り値は、メイン関数の戻り値としてexit関数を呼び出すことと同等ですその引数; 11)main関数を終了する}に到達すると、値0が返されます。戻り型がintと互換性がない場合、ホスト環境に返される終了ステータスは指定されていません。

C++のルールは、他の回答で述べたように少し異なります。

0
dbush

実際、IS mainexit(0)return(0)の違いは、main関数が複数回呼び出された場合です。

次のプログラム

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

int main(int argc, char** argv) {
  if (argc == 0)
    return(0);
  printf("%d", main(argc - 1, argv));
}

として実行

./program 0 0 0 0

次の出力になります。

00000

しかし、これは:

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

int main(int argc, char** argv) {
  if (argc == 0)
    exit(0);
  printf("%d", main(argc - 1, argv));
}

引数に関係なく、何も出力しません。

誰もあなたのmainを明示的に呼び出さないと確信している場合、それは一般的に技術的に大きな違いではありませんが、より明確なコードを維持するためにexitはより良く見えます。何らかの理由でmainを呼び出したい場合は、必要に応じて調整してください。

Cについて話す.

0
radrow