Действительно ли использовать стандартное имя библиотечной функции в качестве идентификатора в C++?

Рассмотрим следующую программу:

#include <cstdio>
int main()
{
    int printf=9;
    std::printf("%d",printf);
}

Можно ли использовать имя встроенной функции в качестве идентификатора в объявлении переменной? Это четко определенная программа? Я имею в виду, хорошо ли определено поведение вышеуказанной программы? Мне любопытно узнать, позволяет ли стандарт C++ использовать стандартные имена функций в качестве идентификаторов переменных

5 ответов

Решение

Это хорошо сформировано, потому что ни std::printf ни ::printf (который также может быть объявлен <cstdio>!) объявляются в той же области видимости, что и ваше целое число, поэтому автоматическое преимущество имеет продолжительность блока.

[C++14: 3.3.1/1]: [..] Чтобы определить объем объявления, иногда удобно обратиться к потенциальному объему объявления. Область объявления совпадает с ее потенциальной областью, если только потенциальная область не содержит другую декларацию с тем же именем. В этом случае потенциальная область объявления во внутренней (содержащейся) декларативной области исключается из области действия декларации во внешней (содержащей) декларативной области.

Например, вы вообще не сможете сделать это в области имен.

Он четко определен, потому что имена объектов в стандартной библиотеке не являются зарезервированными по своей природе:

[C++14: 2.11/3]: Кроме того, некоторые идентификаторы зарезервированы для использования реализациями C++ и стандартными библиотеками (17.6.4.3.2) и не должны использоваться иначе; Диагностика не требуется.

[C++14: 17.6.4.3.2/1]: Определенные наборы имен и сигнатур функций всегда зарезервированы для реализации:

  • Каждое имя, которое содержит двойное подчеркивание _ _ или начинается с подчеркивания, за которым следует заглавная буква (2.12), зарезервировано для реализации для любого использования.
  • Каждое имя, которое начинается со знака подчеркивания, зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен.

Да, это хорошо определенное поведение. Вы создаете int с именем printf, и в настоящее время в вашей области видимости нет ничего с именем printf. В стандартной области и, возможно, в глобальной области есть что-то с именем printf, но int printf, определенный в локальной области, автоматически имеет приоритет.

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

Это ужасная идея, чтобы использовать это.

И будьте осторожны, что могут быть проблемы с этим подходом. Например:

#define NULL 0

int main()
{
     int NULL = 42;
     printf("%d", NULL);
}

не допускается, так как NULL является макросом, а не идентификатором области видимости.

Изменить: я бы добавил, что printf не является "встроенной функцией". Это "стандартная библиотечная функция C". Функция bultin это что-то вроде __builtin_sin, о котором "знает" компилятор, чтобы его можно было оптимизировать. Обратите внимание, что встроенные функции обычно используют "зарезервированные имена", чтобы избежать столкновения с существующей библиотекой и пользовательскими именами в любое время.

Это нормально, чтобы сделать это. Потому что переменная int printf вы определили не принадлежат к пространству имен std как printf, который определен в cstdio, Таким образом, в именах вашей программы нет конфликта.

Однако, если вы объявите

using namespace std;

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

#include<cstdio>
using namespace std;

int main()
{
    int printf = 42;
    printf("%d", printf);
}

Компилятор вернет

error: ‘printf’ cannot be used as a function

Это потому, что в этой программе printf определяется как int в объеме функции, и как функция int printf( const char* format, ... ) в глобальном масштабе. Так как область действия функции меньше глобальной области видимости, в функции int main(), printf интерпретируется как int а не функция. int не вызывается, поэтому сообщение об ошибке.

По сравнению с идентификаторами в стандартных библиотеках стандарт C++ устанавливает только следующую реструктуризацию для идентификаторов.

3 Кроме того, некоторые идентификаторы зарезервированы для использования реализациями C++ и стандартными библиотеками (17.6.4.3.2) и не должны использоваться иначе; Диагностика не требуется.

И (17.6.4.3.2 Глобальные имена)

1 Определенные наборы имен и сигнатур функций всегда зарезервированы для реализации:

- Каждое имя, которое содержит двойное подчеркивание _ _ или начинается с подчеркивания, за которым следует заглавная буква (2.12), зарезервировано для реализации для любого использования.

- Каждое имя, которое начинается со знака подчеркивания, зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен.

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

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

Другие вопросы по тегам