_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.
В общем, примерно понятно, хотя, на мой взгляд, всё равно выглядит как микрооптимизация.
некоторые странные люди собирают свои проекты с -Wall -Wextra -Werror. при этом какой-нибудь код:
int foo()
{
if(a) return b;
else halt();
}
не соберётся. и нужно либо ставить фиктивный return в конце, либо объявлять halt с атрибутом noreturn. второй метод по мне выглядит изящней.
Комментарий для zg.livejournal.com:
__Noreturn, вроде, warning даёт. А на него далеко не все внимание обращают или отключают их вовсе.
А -Werror делает из них ошибки — что и требовалось.
Комментарий для Евгения Степанищева:
нет:
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»
Комментарий для zg.livejournal.com:
это нестандартный noreturn, а я про стандартный _Noreturn
Комментарий для zg.livejournal.com:
Вот с дефольтными ключами:
Комментарий для Евгения Степанищева:
а зачем вы halt объявили как noreturn, а в теле функции написали return?
Комментарий для zg.livejournal.com:
Чтобы показать варнинг о котором речь идёт.
Комментарий для Евгения Степанищева:
так если неправильно _Noreturn пользоваться, конечно варнинг будет.
Комментарий для zg.livejournal.com:
Почему неправильно-то? Смысл его ещё и в том, как мне видится, чтобы показывать программисту где он ошибся — поставил return в функции, откуда не должно быть возврата.