Правила использования символа подчеркивания в идентификаторах C++
Основные правила стандарта C++
Стандарт C++ (раздел 17.4.3.1.2 в старых версиях, 6.1 в новых) четко определяет, какие идентификаторы с подчеркиванием зарезервированы. Нарушение этих правил приводит к неопределенному поведению (UB) — код может работать сегодня, но сломаться при смене компилятора или версии стандартной библиотеки.
Категорический запрет (никогда не используйте)
- Двойное подчеркивание в любом месте: имена, содержащие
__(два подчеркивания подряд) — зарезервированы для реализации (компилятора и стандартной библиотеки). Примеры:__foo,bar__baz,__. - Подчеркивание + заглавная буква в начале: имена, начинающиеся с
_и следующей заглавной буквы — зарезервированы. Примеры:_Foo,_MyClass.
Ограниченное использование (только в определенных контекстах)
- Подчеркивание в начале + строчная буква: зарезервировано в глобальной области видимости. В локальной области (внутри функции, класса) использовать можно, но это плохая практика. Пример:
int _value;на глобальном уровне — нарушение; внутри функции — технически допустимо, но не рекомендуется. - Подчеркивание в конце: полностью разрешено в любом контексте. Это популярный способ избежать конфликтов с ключевыми словами или стандартными именами. Пример:
class_,value_.
Почему такие строгие правила?
Компиляторы и стандартные библиотеки используют подчеркивания для внутренних нужд. Например, __cplusplus — макрос, _M_engine — внутреннее поле в GCC. Если ваш код случайно совпадет с таким именем, возникнет конфликт. Стандарт резервирует эти пространства имен, чтобы:
- Обеспечить совместимость между разными компиляторами
- Дать разработчикам компиляторов свободу в выборе внутренних имен
- Защитить пользовательский код от случайных коллизий
Практические рекомендации (best practices)
// ❌ НЕПРАВИЛЬНО (зарезервировано)
int _Value = 5; // подчеркивание + заглавная
int __value = 10; // двойное подчеркивание
int _global = 20; // подчеркивание + строчная в глобальной области
// ✅ ПРАВИЛЬНО (безопасно)
int value_ = 5; // подчеркивание в конце
int my_value = 10; // подчеркивание между словами
int _local = 20; // ТОЛЬКО внутри функции/класса (но лучше избегать)
// ⚠️ ДОПУСТИМО, но не рекомендуется
void foo() {
int _temp = 0; // технически разрешено в локальной области
}
Исключения из правил
Некоторые имена с двойным подчеркиванием разрешены стандартом, если они определены в самом стандарте (например, __func__, __LINE__, __FILE__). Но их нельзя определять самостоятельно — их предоставляет компилятор.
Итог: безопасное правило — используйте подчеркивание только в середине или в конце имени. Никогда не начинайте имя с подчеркивания, если вы не пишете код внутри стандартной библиотеки или компилятора.
<<Альтернативный взгляд: практика крупных проектов
Хотя стандарт допускает использование _ со строчной буквой в локальной области, многие крупные проекты (Google, LLVM, Qt) полностью запрещают любые идентификаторы, начинающиеся с подчеркивания. Причины:
- Читаемость: подчеркивание в начале часто воспринимается как "внутренняя" или "приватная" переменная, что сбивает с толку.
- Переносимость: код, который сегодня работает в локальной области, завтра может быть перемещен в глобальную при рефакторинге.
- Единообразие: проще запомнить одно правило "не используй подчеркивание в начале" вместо трех.
Вместо этого используйте:
// Плохо: int _counter;
// Хорошо: int counter_;
// Или: int counter; (если нет конфликта)
Если вам нужно обозначить приватное поле класса, используйте m_ (Microsoft-style) или просто суффикс _ (стандарт C++ Core Guidelines). Например: int m_value; или int value_;.
Это упрощает код и делает его безопасным для любых компиляторов и версий C++.