В С++ часто называют имена переменных-членов с каким-то префиксом, чтобы обозначать тот факт, что они являются переменными-членами, а не локальными переменными или параметрами. Если вы пришли из фона MFC, вы, вероятно, используете m_foo
. Иногда я видел myFoo
.
С# (или, возможно, просто .NET), похоже, рекомендует использовать только подчеркивание, как в _foo
. Это разрешено стандартом С++?
Ответ 1
Правила (которые не изменились в C++ 11):
- Зарезервировано в любой области, в том числе для использования в качестве макросов реализации:
- идентификаторы, начинающиеся со знака подчеркивания, за которыми сразу следует заглавная буква
- идентификаторы, содержащие соседние подчеркивания (или "двойное подчеркивание")
- Зарезервировано в глобальном пространстве имен:
- идентификаторы, начинающиеся с подчеркивания
- Кроме того, все в пространстве имен
std
зарезервировано. (Вы можете добавить шаблонные специализации, хотя.)
Из стандарта 2003 C++:
17.4.3.1.2 Глобальные имена [lib.global.names]
Определенные наборы имен и сигнатур функций всегда зарезервированы для реализации:
- Каждое имя, которое содержит двойное подчеркивание (
__
) или начинается с подчеркивания, за которым следует заглавная буква (2.11), зарезервировано для реализации для любого использования. - Каждое имя, которое начинается со знака подчеркивания, зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен. 165
165) Такие имена также зарезервированы в пространстве имен ::std
(17.4.3.1).
Поскольку C++ основан на стандарте C (1.1/2, C++ 03), а C99 является нормативным справочным документом (1.2/1, C++ 03), они также применяются в стандарте C 1999 года:
7.1.3 Зарезервированные идентификаторы
Каждый заголовок объявляет или определяет все идентификаторы, перечисленные в связанном с ним подпункте, и, необязательно, объявляет или определяет идентификаторы, перечисленные в соответствующем подпункте будущих направлений библиотеки, и идентификаторы, которые всегда зарезервированы либо для любого использования, либо для использования в качестве идентификаторов области файла.
- Все идентификаторы, которые начинаются со знака подчеркивания, а также заглавной буквы или другого знака подчеркивания, всегда зарезервированы для любого использования.
- Все идентификаторы, которые начинаются с подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с областью действия файла как в обычном пространстве, так и в пространстве имен тега.
- Каждое имя макроса в любом из следующих подпунктов (включая будущие направления библиотеки) зарезервировано для использования, как указано, если включен какой-либо из связанных с ним заголовков; если прямо не указано иное (см. 7.1.4).
- Все идентификаторы с внешней связью в любом из следующих подпунктов (включая будущие направления библиотеки) всегда зарезервированы для использования в качестве идентификаторов с внешней связью. 154
- Каждый идентификатор с областью файла, указанной в любом из следующих подпунктов (включая будущие направления библиотеки), зарезервирован для использования в качестве имени макроса и в качестве идентификатора с областью файла в том же пространстве имен, если включен какой-либо из связанных с ним заголовков.
Другие идентификаторы не зарезервированы. Если программа объявляет или определяет идентификатор в контексте, в котором она зарезервирована (за исключением случаев, разрешенных в 7.1.4), или определяет зарезервированный идентификатор как имя макроса, поведение не определено.
Если программа удаляет (с помощью #undef
) любое макроопределение идентификатора в первой группе, указанной выше, поведение не определено.
154) Список зарезервированных идентификаторов с внешней связью включает в себя errno
, math_errhandling
, setjmp
и va_end
.
Другие ограничения могут применяться. Например, стандарт POSIX резервирует множество идентификаторов, которые могут отображаться в обычном коде:
- Имена, начинающиеся с заглавной буквы
E
после цифры или заглавной буквы: - может использоваться для дополнительных имен кодов ошибок.
- Имена, начинающиеся с
is
или to
за которыми следует строчная буква - может использоваться для дополнительного тестирования символов и функций преобразования.
- Имена, которые начинаются с
LC_
за которым следует заглавная буква - может использоваться для дополнительных макросов, определяющих атрибуты локали.
- Имена всех существующих математических функций с суффиксом
f
или l
зарезервированы - для соответствующих функций, которые работают с плавающими и длинными двойными аргументами, соответственно.
- Имена, которые начинаются с
SIG
за которым следует заглавная буква, зарезервированы - для дополнительных имен сигналов.
- Имена, которые начинаются с
SIG_
за которым следует заглавная буква, зарезервированы - для дополнительных сигнальных действий.
- Имена, начинающиеся с
str
, mem
или wcs
за которыми следует строчная буква, зарезервированы - для дополнительных строковых и массивных функций.
- Имена, начинающиеся с
PRI
или SCN
за которыми следует любая строчная буква или X
, зарезервированы - для дополнительных макросов спецификатора формата
- Имена, заканчивающиеся на
_t
, зарезервированы - для дополнительных имен типов.
Хотя использование этих имен в ваших собственных целях в настоящее время может не вызывать проблем, они повышают вероятность конфликта с будущими версиями этого стандарта.
Лично я просто не начинаю идентификаторы с подчеркивания. Новое дополнение к моему правилу: нигде не используйте двойные подчеркивания, что легко, так как я редко использую подчеркивание.
После исследования этой статьи я больше не заканчиваю свои идентификаторы _t
поскольку это зарезервировано стандартом POSIX.
Правило о любом идентификаторе, оканчивающемся на _t
меня очень удивило. Я думаю, что это стандарт POSIX (пока не уверен), требующий пояснений, официальных главы и стиха. Это из руководства по GNU libtool, в котором перечислены зарезервированные имена.
CesarB предоставил следующую ссылку на зарезервированные символы POSIX 2004 и отмечает, что "там можно найти много других зарезервированных префиксов и суффиксов...". Зарезервированные символы POSIX 2008 определены здесь. Ограничения несколько более нюансированы, чем указанные выше.
Ответ 2
Правила, позволяющие избежать столкновения имен, находятся в стандарте С++ (см. книгу Stroustrup) и упомянуты гуру С++ (Sutter и т.д.).
Персональное правило
Поскольку я не хотел разбираться с делами и хотел простое правило, я разработал личный, который является простым и правильным:
При присвоении имени символу вы избегаете столкновения с библиотеками компилятора/ОС/стандарта, если вы:
- никогда не начинайте символ с подчеркивания
- никогда не называйте символ с двумя последовательными символами подчеркивания внутри.
Конечно, помещение вашего кода в уникальное пространство имен также помогает избежать столкновения (но не защитит от злых макросов)
Некоторые примеры
(Я использую макросы, потому что они больше загрязняют код символами C/С++, но это может быть что угодно: от имени переменной до имени класса)
#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT
Выдержки из С++ 0x черновик
Из файла n3242.pdf (я ожидаю, что окончательный стандартный текст будет похож):
17.6.3.3.2 Глобальные имена [global.names]
Определенные наборы имен и сигнатур функций всегда зарезервированы для реализации:
- Каждое имя, содержащее двойное подчеркивание _ _ или начинающееся с символа подчеркивания, за которым следует заглавная буква (2.12), зарезервировано для реализации для любого использования.
- Каждое имя, начинающееся с символа подчеркивания, зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен.
Но также:
17.6.3.3.5 Пользовательские суффиксы литерала [usrlit.suffix]
Литеральные идентификаторы суффиксов, которые не начинаются с подчеркивания, зарезервированы для будущей стандартизации.
Это последнее предложение сбивает с толку, если вы не считаете, что имя, начинающееся с одного подчеркивания и сопровождаемое строчной буквой, будет ОК, если not определено в глобальном пространстве имен...
Ответ 3
От MSDN:
Использование двух последовательных символов подчеркивания (__) в начале идентификатора или одного ведущего подчеркивания, за которым следует заглавная буква, зарезервировано для реализаций С++ во всех областях. Вам следует избегать использования одного ведущего подчеркивания, за которым следует строчная буква для имен с областью файлов из-за возможных конфликтов с текущими или будущими зарезервированными идентификаторами.
Это означает, что вы можете использовать одно подчеркивание в качестве префикса переменной-члена, если оно следует за строчной буквой.
Это, очевидно, взято из раздела 17.4.3.1.2 стандарта С++, но я не могу найти исходный источник для полного стандартного онлайн.
См. также этот вопрос.
Ответ 4
Что касается другой части вопроса, то обычно стоит поставить знак подчеркивания в конце имени переменной, чтобы не столкнуться с чем-либо внутренним.
Я делаю это даже внутри классов и пространств имен, потому что мне нужно запомнить только одно правило (по сравнению с "в конце имени в глобальной области видимости и началом имени везде" ).
Ответ 5
Да, символы подчеркивания могут использоваться в любом месте идентификатора. Я считаю, что правила: любой из a-z, A-Z, _ в первом символе и те + 0-9 для следующих символов.
Префикс подчеркивания распространен в коде C - одно подчеркивание означает "private", а двойные символы подчеркивания обычно зарезервированы для использования компилятором.