`_Noreturn`/`noreturn` 함수 지정자

_Noreturn/noreturn 함수 지정자

함수를 호출했는데 절대로 호출한 지점으로 돌아오지 않는 경우가 있어요. 예를 들어 프로그램을 종료하는 exit()이라거나, 오류 상황에서 바로 종료하는 함수들요. 그런 함수를 컴파일러에게 알려주면, 컴파일러가 "이 함수 뒤의 코드는 실행되지 않으니 경고 없이 넘어가자" 하고 확실히 처리할 수 있어요. 그 역할을 하는 게 _Noreturn(C23부터는 [[noreturn]] 속성) 함수 지정자예요.

출처: cppreference

본문

_Noreturn 키워드는 함수 선언에 등장해서, 그 함수가 return 문을 실행하거나 함수 본문 끝까지 도달해서 제어를 되돌리지 않는다는 걸 지정해요. 다만 longjmp로 빠져나가는 것은 가능해요. 만약 _Noreturn으로 선언한 함수가 실제로 돌아온다면, 동작은 정의되지 않아요(undefined behavior). 컴파일러가 그걸 감지할 수 있으면 진단(diagnostic)을 내리도록 권장돼요.

문법

_Noreturn function_declaration (since C11)(C23에서 deprecated)

_Noreturn 지정자는 같은 함수 선언에 여러 번 나와도 되는데, 그 경우 한 번 나온 것과 동일하게 동작해요.

이 지정자는 보통 <stdnoreturn.h> 헤더가 제공하는 편의 매크로 noreturn을 통해 써요.

C23부터 _Noreturn 함수 지정자와 매크로 noreturn 모두 deprecated됐고, 대신 [[noreturn]] 속성을 쓰는 게 권장돼요.

키워드

_Noreturn

표준 라이브러리에서의 noreturn 함수

표준 라이브러리에서 noreturn인 함수는 다음과 같아요.

  • abort()
  • exit()
  • _Exit()
  • quick_exit()
  • thrd_exit()
  • longjmp()

예시

여기서는 i가 0보다 크면 종료하고, 그렇지 않으면 정의되지 않은 동작을 일으키는 함수를 만들어 봐요.

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

// causes undefined behavior if i <= 0
// exits if i > 0
noreturn void exit_now(int i) // or _Noreturn void exit_now(int i)
{
    if (i > 0)
        exit(i);
}

int main(void)
{
    puts("Preparing to exit...");
    exit_now(2);
    puts("This code is never executed.");
}

출력:

Preparing to exit...

exit_now(2)가 프로그램을 종료시키기 때문에, 그 뒤의 puts("This code is never executed.")는 실행되지 않아요. noreturn 덕분에 컴파일러는 이 점을 확실히 알고 있어요.

더 알아보기

  • C23부터는 이 함수 지정자 대신 [[noreturn]] 속성을 쓰는 걸 권장해요.
  • 함수 선언과 정의의 전반은 함수 문서에서 볼 수 있어요.
  • cppreference의 _Noreturn 원문에서 참조 기록을 확인할 수 있어요.