Правила использования подчеркивания "_" в именах

Рейтинг: 12Ответов: 1Опубликовано: 19.04.2015

В различных источниках встречаются упоминания того, что нельзя использовать идентификаторы с несколькими подчеркиваниями, или что нельзя называть параметры шаблона _Ty.
При этом заголовочных файлах стандартной библиотеки только такие имена и используются.
Почему так? Как надо писать правильно?

Ответы

▲ 14Принят

C++

В главе Identifiers [lex.name] сказано, что некоторые идентификаторы зарезервированы, и могут быть использованы только компилятором и стандартной библиотекой:

  • зарезервировано любое имя, которое содержит двойное подчеркивание (__), или начинается с подчеркивания и следующей за ним большой буквой;
  • в глобальном пространстве имен, зарезервировано любое имя, которое начинается с подчеркивания.

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

Примеры:

void _f(); // запрещено
class X {
  int _m; // OK
  int _M; // запрещено
};
namespace N {
  int _1;     // OK
  void _f();  // OK
  class X__Y; // запрещено
}

Почему так сделано?

Это дает гарантию, что имена в стандартной библиотеке не будут пересекаться с пользовательским кодом. Например если написать

#define X
struct Y;
#include <vector>

то определение имен X и Y ничего не сломают в стандартных заголовочных файлах, и наоборот, если написать

#include <vector>
struct X;

то никакие имена, определенные в стандартных заголовочных файлах не помешают определить X.

Также стандартная библиотека может использовать имена вида ::_f в своей реализации, тогда конфликт имен приведет к нарушению One Definition Rule, что обычно проявляется в виде ошибок линковки.

C

Аналогичные правила используются и в Си.
В главе "7.1.3 Reserved identifiers" приведен список зарезервированных идентификаторов:

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