Cのreturn nとexit(n)の間に違いはありますか?


9

return nmain関数の)とexit(n)Cの間に違いはありますか?CまたはPOSIX標準で定義されていますか、それともOSまたはコンパイラに依存していますか?

回答:


5

ほとんどの場合、そこには違いませんが、ここでは、使用しているかどうかに応じて、異なる動作をする可能性がありますCのプログラムですreturn 0;exit(0);

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

static char *message;

void cleanup(void) {
    printf("message = \"%s\"\n", message);
}

int main(void) {
    char local_message[] = "hello, world";
    message = local_message;
    atexit(cleanup);
#ifdef USE_EXIT
    puts("exit(0);");
    exit(0);
#else
    puts("return 0;");
    return 0;
#endif
}

以下のためatexit()のいずれか、コールexit(0);またはreturn 0;原因となるcleanup関数が呼び出されます。違いは、プログラムがを呼び出すとexit(0);、「呼び出し」main()がまだアクティブな間にクリーンアップが行われるため、local_messageオブジェクトがまだ存在することです。実行return 0;、しかし、すぐに呼び出しを終了main()し、その後、起動するcleanup()機能を。以来cleanup()(グローバル介し意味messageに局所的に割り当てられていないのオブジェクトへのポインタ)main、そのオブジェクトがもはや存在し、動作が未定義です。

これが私のシステムでの動作です。

$ gcc -DUSE_EXIT c.c -o c && ./c
exit(0);
message = "hello, world"
$ gcc c.c -o c && ./c
return 0;
message = ""
$ 

を使用せずにプログラムを実行する-DUSE_EXITと、クラッシュや印刷"hello, world"(使用されているメモリlocal_messageが破損しない場合)など、何もできません。

ただし、実際には、この違いは、内部でローカルに定義されたオブジェクトmain()main()、それらへのポインターを保存することによって外部で可視化される場合にのみ現れます。これはもっともらしいことですargv。(私のシステムでの実験では、によってポイントされたオブジェクトとオブジェクトによってポイントされたオブジェクトが、から戻った後も存在argv*argv続けることを示していますmain()が、それに依存するべきではありません。)


16
  • C
    の場合標準では、最初の呼び出しからmainへの戻りは、exitの呼び出しと同等であると述べています。ただし、クリーンアップ中にメインのローカルデータが必要になる場合、メインからの戻りが機能するとは期待できません。

  • C ++の場合

exit(0)を使用してプログラムを終了する場合、ローカルスコープの非静的オブジェクトのデストラクタは呼び出されません。ただし、戻り値0を使用すると、デストラクタが呼び出されます。

プログラム1 –-exit(0)を使用して終了します

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

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};

int main() {
  Test t1;

  // using exit(0) to exit from main
  exit(0);
}

出力:内部テストのコンストラクター

プログラム2 – return 0を使用して終了

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

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
  }
};

int main() {
  Test t1;

   // using return 0 to exit from main
  return 0;
}

出力:Inside Test's Constructor
Inside Test's Destructor

たとえば、デストラクタにファイルを閉じるなどのリソースを解放するコードがある場合、デストラクタの呼び出しが重要になることがあります。

静的オブジェクトは、exit()を呼び出してもクリーンアップされることに注意してください。たとえば、次のプログラムを参照してください。

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

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};

int main() {
  static Test t1;  // Note that t1 is static

  exit(0);
}

出力:Inside Test's Constructor
Inside Test's Destructor


プログラムの終了時にファイルが閉じられるため、ファイルを閉じることは、終了時に起動する重要なデストラクタの良い例ではありません。
Winston Ewert、2012年

1
@WinstonEwert:True、ただしフラッシュする必要があるアプリケーションレベルのバッファーが存在する可能性があります。
Philipp

1
質問はC ++についてはどこにも触れていません...
tdammers '28 / 10/28

私はどちらの言語も知らないので許しますが、この答えは、exitがC#のフェイルファストのようであると思います。
ジミーホファ2012年

@ JimmyHoffa、C ++にはありませんfinally
Winston

6

C標準(C99)は、2つのタイプの実行環境、独立型環境ホスト型環境を定義していることに注意してください。フリースタンディング環境は、CライブラリをサポートしないC環境であり、組み込みアプリケーションなどを対象としています。CライブラリをサポートするAC環境は、ホスト環境と呼ばれます。

C99によると、自立環境ではプログラムの終了は実装で定義されます。そのため、実装定義されている場合mainreturn nおよびexit、彼らの行動は、としてその実装で定義されています。

C99は、ホスト環境の動作を次のように定義しています。

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


1
そして、独立した環境からexit()を呼び出すことは、まったく意味がありません。exit()と同等の機能は、プログラムを永久ループでハングさせ、ウォッチドッグがタイムアウトするのを待ちます。

0

C標準の観点から、returnステートメントではexit()なく、関数であること以外は、実際にはそうではありません。どちらを使用しても、登録されatexit()ている関数が呼び出され、プログラムが終了します。

注意が必要な状況がいくつかあります。

  • の再帰main()。実際にはめったに見られませんが、Cでは合法です(C ++では明示的に禁止しています)。
  • の再利用main()。場合によっては、既存のmain()ものは別の名前に変更され、新しいによって呼び出されmain()ます。

を使用するとexit()、コードの記述後にこれらのいずれかが発生した場合、特に異常終了しない場合にバグが発生します。それを避けるために、それをmain()関数として扱い、return終了させたいときに使用する習慣をつけるのは良い考えです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.