Правила использования подчёркивания в именах идентификаторов C++
Основные правила стандарта C++ для подчёркиваний в идентификаторах
В C++ использование подчёркивания в именах строго регламентировано стандартом (начиная с C++03 и по C++23). Это сделано для того, чтобы избежать конфликтов с именами, зарезервированными для реализации компилятора, стандартной библиотеки и макросов препроцессора. Нарушение этих правил приводит к неопределённому поведению (undefined behavior), то есть программа может работать, а может и нет — компилятор не обязан выдавать ошибку.
Четыре главных правила (запомните их)
- Правило 1: Идентификатор, содержащий два последовательных подчёркивания (
__) в любом месте, всегда зарезервирован для реализации. Примеры:__myVar,my__var,myVar__. - Правило 2: Идентификатор, начинающийся с подчёркивания и следующей за ним заглавной буквы (
_A,_B,_Z), зарезервирован для реализации. Пример:_MyClass. - Правило 3: Идентификатор, начинающийся с подчёркивания в глобальной области видимости (не внутри класса, функции или пространства имён), зарезервирован для реализации. Пример:
_globalVarна уровне файла. - Правило 4: Все идентификаторы, начинающиеся с подчёркивания, в любом месте, зарезервированы для реализации в пространстве имён std. То есть нельзя объявлять свои имена вида
std::_foo.
Когда можно использовать подчёркивание?
Внутри классов, функций или пространств имён (не в глобальной области) вы можете использовать подчёркивание в начале имени, если следующая буква — строчная (не заглавная). Это традиционный стиль для приватных членов класса (m_ или просто _). Например:
class MyClass {
private:
int _value; // OK: внутри класса, после _ идёт строчная буква
int __value; // ОШИБКА: два подчёркивания запрещены всегда
int _Value; // ОШИБКА: после _ идёт заглавная буква
public:
int getValue() const { return _value; }
};
void myFunction() {
int _localVar; // OK: внутри функции, после _ строчная буква
}
Почему _main выдаёт предупреждение?
Имя _main начинается с подчёркивания и находится в глобальной области видимости (на уровне файла). Согласно правилу 3, это зарезервированное имя. Компилятор может выдать предупреждение (или ошибку), потому что такое имя может конфликтовать с внутренними символами реализации (например, в некоторых системах _main — это точка входа в программу на ассемблерном уровне). Аналогично, __LINE__ — это имя, начинающееся с двух подчёркиваний, что нарушает правило 1. К тому же __LINE__ — это предопределённый макрос препроцессора, его нельзя переопределять.
Как правильно использовать подчёркивание?
Для разделения слов в длинных идентификаторах (snake_case) используйте одиночное подчёркивание в середине имени, но никогда в начале (если это не приватный член класса со строчной буквой после подчёркивания). Примеры:
int my_variable_name; // OK: snake_case
void process_user_input(); // OK
class data_processor { ... }; // OK
int _my_variable; // OK только внутри функции/класса (строчная после _)
int my_variable_; // OK, но не рекомендуется (trailing underscore)
Рекомендации по стилю (не обязательные, но общепринятые)
- Не используйте подчёркивание в начале имени для обычных переменных и функций — это может случайно нарушить правила.
- Для приватных членов класса часто используют
m_(например,m_value) или просто_со строчной буквой — но это стиль, а не правило языка. - Для констант и макросов используйте
ALL_CAPS(все заглавные с подчёркиваниями), но избегайте двойных подчёркиваний. - Никогда не начинайте идентификатор с подчёркивания в глобальной области — это почти гарантированно приведёт к неопределённому поведению в будущем.
Итог
Запомните три «красных флага»: два подчёркивания подряд, подчёркивание + заглавная буква, подчёркивание в глобальной области. Всё остальное (одиночное подчёркивание со строчной буквой внутри класса/функции) — допустимо, хотя и не всегда рекомендуется. Если сомневаетесь — просто используйте snake_case без начального подчёркивания.
Дополнительный взгляд: почему стандарт такой строгий?
Правила кажутся избыточными, но у них есть практическая причина. Компиляторы и стандартная библиотека C++ активно используют имена с подчёркиванием для внутренних нужд. Например, _M_ в GCC или __ в Microsoft VC++. Если бы программист мог случайно создать переменную с именем _Lock (заглавная L), она могла бы пересечься с внутренним макросом библиотеки, что привело бы к трудноуловимым ошибкам.
Что делать, если очень хочется подчёркивание в начале?
Если вы пишете код только для себя и на одном компиляторе, вы можете использовать _value (строчная после _) внутри класса — это работает. Но при переносе кода на другой компилятор или при обновлении стандарта могут возникнуть проблемы. Лучший способ — использовать суффикс или префикс, который гарантированно не зарезервирован:
- Префикс
m_(от member) —m_value - Суффикс
_—value_ - Просто
valueбез подчёркивания
Проверка на практике
Если вы пишете библиотеку, которая должна быть переносимой, используйте статический анализатор (например, clang-tidy с правилом readability-identifier-naming). Он предупредит о нарушении правил резервирования. Для учебных проектов достаточно запомнить: два подчёркивания и подчёркивание с заглавной — табу.
Ответов пока нет.
Войдите чтобы оставить ответ