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" приведен список зарезервированных идентификаторов:
- все которые начинаются с
_
и следующей за ним большой буквы или _
;
- те которые начинаются с
_
в области видимости файла, и находятся в обычном пространстве имен или пространстве имен тегов (в отличие от С++, разрешено двойное подчеркивание в середине и в конце имени);
- имена макросов, приведенные в стандарте, если переопределение не разрешено явно;
- имена с внешним связыванием, приведенные в стандарте, зарезервированы для имен с внешним связыванием;
- имена из стандартных заголовочных файлов, если подключен соответствующий заголовочный файл.