__функция__ определение внешней функции

# #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 за подробное объяснение, а не только за педантичную цитату .