Может ли совместимый со стандартами C assert () оценивать свой аргумент несколько раз?

является стандартным C assert(e) макрос позволяющий оценить e несколько раз? Как насчет C++11 или более поздней версии? Я не вижу никаких гарантий в спецификация открытой группы, и ответ не очевиден для меня с некоторых поисков (1, 2).

контекст: может func() вызывается несколько раз в assert(func() != NULL)?

Да, я уже знаю, что это плохая идея по другим причинам: как руководство glibc указывает, аргумент assert() не будет оцениваться вообще, если NDEBUG определяется. Однако, предполагая, что NDEBUG is не определено, есть ли гарантия на максимум количество раз e оценивается?

вопрос, заданный этот.

1 ответов


стандарт C говорит

в стандарте C11 (ISO / IEC 9899: 2011), §7.1.4 использование библиотечных функций говорит:

каждое из следующих утверждений применяется, если явно не указано иное в следующих подробных описаниях:...

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

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

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

#define abs(x) _BUILTIN_abs(x)

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

#undef abs

обеспечивает ли заголовок реализации реализацию макроса abs или встроенная реализация. Таким образом, также обнаруживается прототип функции, который предшествует и скрыт любым макро-определением.

преамбула в §7.2 Диагностика <assert.h> говорит:

на assert макрос должен быть реализован как макрос, а не функция. Если макрос определение подавляется для доступа к фактической функции, поведение не определено.

и раздел §7.2.1.1 на assert макрос говорит:

на assert макрос помещает диагностические тесты в программы; он расширяется до выражения void. Когда он выполняется, если expression (который должен иметь скалярный тип) является ложным (то есть сравнивает равным 0),assert макрос записывает информацию о конкретном вызове, который не удался (включая текст аргумента, имя исходного файла, исходная строка число и имя заключительной функции-последние являются соответственно значениями макросов предварительной обработки __FILE__ и __LINE__ и идентификатора __func__) в стандартном потоке ошибок в формате, определенном реализацией.191) затем он называет