__func__ вне определения функции

Что должно произойти, если мы используем предопределенную переменную __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.general]

8 Предопределенная переменная local-function __func__ определяется как если бы
определение формы static const char __func__[] = "function-name";
было предоставлено, где имя-функции определяется реализацией
строка. Не указано, имеет ли такая переменная адрес
отличается от любого другого объекта в программе.

ISO / IEC 9899: 2011

6.4.2.2 Предопределенные идентификаторы

1 Идентификатор __func__ неявно объявляется переводчиком, как если бы, немедленно
после открывающей скобки каждого определения функции
декларация static const char __func__[] = "function-name";
где имя-функции — это имя лексически-вмещающего
функция.

UB? Ошибка? Или что-то другое?

21

Решение

Стандарт ничего не говорит об этом явно

Это означает неопределенное поведение.

Из стандарта С (выделено мое):

(C99, 4.p2) «Если требование » должен » или » не должен »», которое появляется вне ограничения, нарушается, поведение не определено. Неопределенное поведение иначе указано в этом международном стандарте словами » «неопределенное поведение» или отсутствием какого-либо явного определения поведения. Нет разницы в акценте между этими тремя; все они описывают «поведение, которое не определено» «.

23

Другие решения

(Повышено из более раннего комментария)

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

Это может быть неопределенным, или это может быть определено как строка, или как что-либо еще, и эта реализация все еще соответствует.

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

Для конкретных примеров того, как код в вопросе может иметь неопределенное поведение при использовании с соответствующей реализацией, я полагаю, что реализация может определить его следующим образом: nullptr (таким образом, в примере printf) или может даже определить его в макрос, который расширяется до разыменования нулевого указателя, а затем #undef это при входе в каждую функцию и #define это после каждой функции (так что пример будет падать до main начинается!)

7