# #gcc #clang #icc #implicit-declaration
Вопрос:
Что должно произойти, если мы используем предопределенную переменную __func__
вне функции в C (C99 / C11) и C ?
#include <stdio.h>
const char* str = __func__;
int main(void)
{
printf("%s", str);
return 0;
}
gcc 4.7.2 выдает только предупреждение (при -Wall -W -pedantic
включенном) и ничего не печатает.
Стандарт ничего не говорит об этом явно:
ISO/IEC 14882:2011
8.4.1 В целом [dcl.fct.def.общие]
8 Предопределенная локальная переменная функции
__func__
определяется так, как еслиstatic const char __func__[] = "function-name";
бы было предоставлено определение формы, где имя функции является строкой, определенной реализацией. Не указано, имеет ли такая переменная адрес, отличный от адреса любого другого объекта в программе.
ISO/IEC 9899:2011
6.4.2.2 Предопределенные идентификаторы
1 Идентификатор
__func__
должен быть неявно объявлен переводчиком, как если бы сразу после открывающей скобки каждого определения функцииstatic const char __func__[] = "function-name";
появилось объявление, где имя функции-это имя лексически заключающей функции.
УБ? Ошибка? Или что-то еще?
Комментарии:
1. Я голосую за ошибку, учитывая формулировку «функция-локальная предопределенная переменная» и «сразу после начальной скобки каждого определения функции» в ваших цитатах.
2. Любое поведение, не определенное стандартом, является, по определению, неопределенным поведением 😉
Ответ №1:
Стандарт ничего не говорит об этом явно
Это означает неопределенное поведение.
Из стандарта C (выделено мной):
(C99, 4.p2) «Если требование ‘должно’ или ‘не должно’, которое появляется за пределами ограничения, нарушается, поведение не определено. Неопределенное поведение иначе обозначается в этом Международном стандарте словами ‘неопределенное поведение’ или отсутствием какого-либо явного определения поведения. Между этими тремя нет разницы в акцентах; все они описывают ‘поведение, которое не определено’.»
Ответ №2:
(Повышено по сравнению с предыдущим комментарием)
__func__
находится в зарезервированном пространстве имен, поэтому реализации разрешено использовать его в области пространства имен для любых целей, т. Е. Реализация не требуется для диагностики (неправильного)использования __func__
вне функции, поскольку ничто в стандарте не запрещает реализации определять __func__
как массив области пространства char
имен, если это то, что хотят сделать разработчики.
Он может быть неопределенным, или он может быть определен как строка, или как что-либо еще, и эта реализация все еще соответствует.
Таким образом, попытка использовать его вне функции является неопределенным поведением, потому что он может быть определен или не определен и может быть или не быть подходящего типа для использования.
Для конкретных примеров того, как код в вопросе может иметь неопределенное поведение при использовании с соответствующей реализации, я считаю, что реализация может определить ее nullptr
(так что пример будет катастрофа В printf
) или может даже определить это макрос, который расширяется до разыменования нулевого указателя, а затем #undef
на вход каждой функции и #define
ее после каждой функции (так что пример будет переночевать, прежде чем main
начинается!)
Комментарии:
1. 1 за подробное объяснение, а не только за педантичную цитату .