Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

_Noreturn в C11

Си — язык на котором я программирую редко, но всё же такое случается. Соответственно слежу что там появляется нового (кстати, есть ребята, которые понятия не имеют, что этот язык вообще развивается).

В относительно недавно вышедшей редакции Си-11 мне всё было понятно, кроме ключевого слова «_Noreturn» — им теперь предлагается маркировать функции из которых нет возврата (например, они вызвали abort, exit, quick_exit или что-то подобное).

Смысла этого я не понимал, но и как-то внимания не обращал. Почему-то недавно это меня заинтересовало по-настоящему, я даже написал знаменитой «Алёне Си++», с которой как-то пересекался, так как работал с её мужем, подумал, что она может следить и за Си, раз пишет на Си++. Вот что она ответила:

Я noreturn  никогда не пользовалась, но насколько я знаю он нужен, когда функция вообще не возвращает значение. В void функции можно сказать ’return;’

Noreturn-функции либо бросают исключения, либо говорят exit в какой-то момент. Если компилятор знает, что из функции возврата нет, то может сделать соответствующую оптимизацию.

За Си не слежу, мне здесь C# полезнее, чем С.

Чуть подробнее об этом написано в описании атрибута «noreturn» компилятора gcc (там есть аналог в виде расширения языка) на примере функции fatal:

The noreturn keyword tells the compiler to assume that fatal cannot return. It can then optimize without regard to what would happen if fatal ever did return. This makes slightly better code. More importantly, it helps avoid spurious warnings of uninitialized variables.

The noreturn keyword does not affect the exceptional path when that applies: a noreturn-marked function may still return to the caller by throwing an exception or calling longjmp.

Do not assume that registers saved by the calling function are restored before calling the noreturn function.

В общем, примерно понятно, хотя, на мой взгляд, всё равно выглядит как микрооптимизация.

10 комментариев
zg (zg.livejournal.com) 2014

некоторые странные люди собирают свои проекты с -Wall -Wextra -Werror. при этом какой-нибудь код:
int foo()
{
  if(a) return b;
  else halt();
}
не соберётся. и нужно либо ставить фиктивный return в конце, либо объявлять halt с атрибутом noreturn. второй метод по мне выглядит изящней.

Евгений Степанищев (bolknote.ru) 2014

Комментарий для zg.livejournal.com:

__Noreturn, вроде, warning даёт. А на него далеко не все внимание обращают или отключают их вовсе.

masterspammer (masterspammer.livejournal.com) 2014

А -Werror делает из них ошибки — что и требовалось.

zg (zg.livejournal.com) 2014

Комментарий для Евгения Степанищева:

__Noreturn, вроде, warning даёт

нет:
C:\>cat test.c
void halt(void);
int foo(int a,int b)
{
  if(a) return b;
  else halt();
}
C:\>g++ -Wall -Wextra -Werror -O3 -c -o «test.o» «test.c»
test.c: In function ’int foo(int, int)’:
test.c:7:1: error: control reaches end of non-void function [-Werror=return-type]
 }
 ^
cc1plus.exe: all warnings being treated as errors
C:\>cat test_nr.c
void halt(void) __attribute__noreturn;
int foo(int a,int b)
{
  if(a) return b;
  else halt();
}
C:\>g++ -Wall -Wextra -Werror -O3 -c -o «test_nr.o» «test_nr.c»

Евгений Степанищев (bolknote.ru) 2014

Комментарий для zg.livejournal.com:

это нестандартный noreturn, а я про стандартный _Noreturn

Евгений Степанищев (bolknote.ru) 2014

Комментарий для zg.livejournal.com:

Вот с дефольтными ключами:

a.c: In function ’halt’:
a.c:2:5: warning: function declared ’noreturn’ has a ’return’ statement [enabled by default]
a.c:2:5: warning: ’noreturn’ function does return [enabled by default]

zg (zg.livejournal.com) 2014

Комментарий для Евгения Степанищева:

Вот с дефольтными ключами:

а зачем вы halt объявили как noreturn, а в теле функции написали return?

Евгений Степанищев (bolknote.ru) 2014

Комментарий для zg.livejournal.com:

Чтобы показать варнинг о котором речь идёт.

zg (zg.livejournal.com) 2014

Комментарий для Евгения Степанищева:

так если неправильно _Noreturn пользоваться, конечно варнинг будет.

Евгений Степанищев (bolknote.ru) 2014

Комментарий для zg.livejournal.com:

Почему неправильно-то? Смысл его ещё и в том, как мне видится, чтобы показывать программисту где он ошибся — поставил return в функции, откуда не должно быть возврата.