LoginSignup
1
1

More than 1 year has passed since last update.

[C言語] exit()と_exit()の違い

Last updated at Posted at 2021-07-30

なんとなく気になったので調べてみました。

  • exit: プログラムの終了時に呼び出されるライブラリ関数(glibc)
  • _exit: exit の中から呼ばれ、exit_group を呼び出すシステムコールラッパー(glibc)
  • exit_group: プログラムを終了させるLinuxのシステムコール(Linux)

大きな違いは、2つありました。
1つ目は、終了時に atexit や on_exit で登録した関数が呼ばれるか。
2つ目は、バッファされた標準入出力データを終了時にフラッシュするか。

実際にどのような挙動になるのか試してみました。

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

void bye(void) // mainが終了したら呼び出される
{
    printf("good bye\n");
}

int main(void)
{
    int i;

    i = atexit(bye); // 正常終了時に呼び出される関数を設定
    if (i != 0) {
        fprintf(stderr, "cannot set exit function\n");
        exit(EXIT_FAILURE);
    }
    printf("good morning\n");
    exit(EXIT_SUCCESS);
}

実行結果

$ ./a.out
good morning
good bye

mainが終了した後に atexit で設定した関数が呼び出されています。
ちなみに exit ではなく、return で終了した場合も実行されます。

次に _exit を使用してみます。

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

void bye(void) // mainが終了したら呼び出される
{
    printf("good bye\n");
}

int main(void)
{
    int i;

    i = atexit(bye); // 正常終了時に呼び出される関数を設定
    if (i != 0) {
        fprintf(stderr, "cannot set exit function\n");
        _exit(EXIT_FAILURE);
    }

    printf("good morning\n");
    _exit(EXIT_SUCCESS);
}

実行結果

$ ./a.out
good morning

atexit で設定した関数が呼び出されませんね。
_exit の場合は呼び出された時点で即座に終了していることが分かります。

atexit とon_exit

ちなみにこの2つも少し違います。
どちらも正常終了時に呼び出される関数を登録する事ができます。
しかし on_exit に関しては、すべてのプラットフォームで互換性があるとは限らないようです。
したがって、atexit の使用が推奨されているみたいです。

バッファリングの違い

違いとして、exit では必ず flush され、_exit では一般に flush されないみたいです。

以下実行例です。

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

int main(void)
{
     printf("hello\nworld");
     exit(0);
}

実行結果

./a.out
hello
world

exit なので、flushされていますね。

次に _exit で終了させます。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
    printf("hello\nworld");
    _exit(0);
}

実行結果

./a.out
hello

world の部分が表示されていません。
flush されていないことが確認できます。

ちなみに fflush を使うことで _exit 前に flush させることもできるみたいです。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
    printf("hello\nworld");
    fflush(stdout);
    _exit(0);
}

実行結果

./a.out
hello
world

flushされていますね。

まとめ

@fujitanozomu さんにバッファリングの違いについて教えていただき勉強になりました。
forkする場合は重複して flush されることを防ぐために、_exit で抜けるのが定番らしいです。
exit と _exit を状況に応じて使い分けたいですね。

1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1