Использование _Noreturn в C11

Возможный дубликат:
Что такое точка атрибута Noreturn?

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

Помимо ценности документации в исходном коде, какие еще преимущества дает этот атрибут и зачем его использовать?


c c11
person user1255770    schedule 03.12.2012    source источник
comment
stackoverflow.com/ questions/10538291/ задает тот же вопрос для C++. Рассуждение для C точно такое же.   -  person Stephen Canon    schedule 04.12.2012
comment
Рассуждение аналогично; синтаксис, по-видимому, полностью отличается между C++ ([[noreturn]]) и C (_Noreturn или noreturn, если вы включили <stdnoreturn.h>). Итак, я бы расценил это как хороший x-ref; Однако я не уверен насчет дубликата.   -  person Jonathan Leffler    schedule 04.12.2012
comment
Номинируйте на повторное открытие, потому что это про C, а другое про C++, два совершенно разных языка. Фактический синтаксис также сильно отличается.   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 17.09.2014


Ответы (3)


Если функция безоговорочно вызывает функцию _Noreturn, компилятор сможет понять, что:

  • последующий код является мёртвым кодом, что позволяет проводить оптимизацию (его можно удалить из сгенерированного бинарного файла) и диагностику — компилятор сможет выдавать предупреждения о недостижимом коде;

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

    Это особенно важно для статических анализаторов кода — количество ложных срабатываний, выдаваемых статическим анализатором CLang в нашем большом приложении, значительно сократилось, как только мы пометили нашу функцию die (регистрировать фатальную ошибку и завершить приложение) как noreturn.

Также может быть доступна какая-то другая оптимизация - поскольку функция никогда не возвращает значение, нет необходимости помещать адрес возврата в стек, сохранять состояние регистров и т. д., все, что нужно, это передать аргументы и выполнить jmp для запуск функции, не беспокоясь о возврате и очистке после возврата. Но, конечно, поскольку вызов одноразовый, производительность для сжатия здесь в основном незначительна.

person Matteo Italia    schedule 03.12.2012
comment
с помощью этого аргумента даже функция, которая возвращает, может быть помечена как _Noreturn, верно?? Пример: int foo(data * arg) { ++arg->count; return bar(arg); } -- функция foo может вызываться с переходом, а затем снова переходить к bar(), где фактически возвращаются данные. Или я упустил момент? - person user666412; 24.08.2015
comment
@ user666412: это оптимизация хвостового вызова, которая в основном не имеет отношения. Применение _Noreturn к bar будет означать, что он никогда не вернется; OTOH, здесь компилятор может просто делегировать очистку bar только в одном конкретном случае. Кроме того, оглядываясь назад, в моем ответе слишком много внимания уделяется аспекту оптимизации (который является маргинальным для функций _noreturn, поскольку они, очевидно, редко вызываются), суть в основном в том, чтобы пометить мертвый код и лучше настроить предупреждения в окружении таких вызовов ( например, если у меня есть функция, которая выполняет exit(1), не имеет значения, возвращает она результат или нет). - person Matteo Italia; 25.08.2015
comment
Все еще кажется слишком много усилий для вызова, который произойдет не более одного раза в программе. - person user666412; 25.08.2015
comment
@ user666412: вот о чем я говорю, аспект времени выполнения в основном незначителен. Смысл в том, чтобы помочь компилятору в анализе потока кода и, таким образом, выдать более качественные предупреждения; пример: в нашем приложении есть функция die, которая убивает приложение, протоколируя, что пошло не так; не помечая его как noreturn, мы получаем несколько ложных предупреждений об отсутствующих return, неинициализированных переменных и т.п. - все это исчезает, как только компилятор понимает, что die никогда не возвращается. - person Matteo Italia; 25.08.2015
comment
@user666412 user666412: переформулировал весь ответ для ясности и лучшей перспективы. - person Matteo Italia; 25.08.2015

__attribute__((noreturn)) или _Noreturn полезны для таких функций, как die():

static __attribute__((noreturn)) void die(const char *fmt, ...) {
     /* print a formatted error message and exit  */
     exit(EXIT_FAILURE);
}
/* And let's say in main() you would want to exit because of an error but unforunately GCC complains about return value.  */
int main() 
{
    if (!whatever)
         die("a nasty error message goes here\n");
}

А также используется для оптимизации, как указано.

person Community    schedule 03.12.2012
comment
[JFYI] Вам не нужно явно возвращаться из функции main() (это остатки совместимости с C) - person AlexT; 03.02.2014
comment
Это был просто пример, чтобы продемонстрировать, что произойдет. - person ; 03.02.2014

Это позволяет компилятору выполнять дополнительные оптимизации. Взгляните здесь на атрибут noreturn GCC, который он поддерживает некоторое время (семантика, вероятно, такая же)

person Kylo    schedule 03.12.2012