Каковы правила использования символа подчеркивания в идентификаторе C++?

В C++ принято называть переменные-члены каким-либо префиксом, чтобы обозначить тот факт, что они являются переменными-членами, а не локальными переменными или параметрами. Если у вас есть опыт работы с MFC, вы, вероятно, будете использовать m_foo. Иногда я видел myFoo.

C# (или, возможно, просто .NET), кажется, рекомендует использовать только подчеркивание, как в _foo. Разрешено ли это стандартом C++?

Страницу руководства glibc об этом можно найти в gnu.org/software/libc/manual/html_node/Reserved-Names.html Edit: см. Также opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.h‌ tml

CesarB 23.10.2008 14:59

Просто отметим, что незнание этих правил не обязательно означает, что ваш код не будет компилироваться или запускаться, но вполне вероятно, что ваш код не будет переноситься на другие компиляторы и версии, поскольку нельзя гарантировать, что не будет имени столкновения. Чтобы подтвердить это, я знаю определенную реализацию важной системы, в которой в качестве соглашения об именах везде используется заглавная буква _. Никаких ошибок из-за этого нет. Конечно, это плохая практика.

g24l 17.11.2015 01:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
961
2
275 441
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Да, символы подчеркивания могут использоваться в любом месте идентификатора. Я считаю, что правила следующие: любой из букв a-z, A-Z, _ в первом символе и + 0-9 для следующих символов.

Префиксы подчеркивания распространены в коде C - одиночное подчеркивание означает «частный», а двойное подчеркивание обычно зарезервировано для использования компилятором.

Они распространены в библиотеках. Они не должны быть обычными в пользовательском коде.

Martin York 23.10.2008 11:12

Знаете, люди делать пишут библиотеки на C.

John Millikin 23.10.2008 21:51
«Да, символы подчеркивания могут использоваться в любом месте идентификатора». Это неверно для глобальных идентификаторов. См. Ответ Роджера.
sbi 09.07.2015 16:39

@sbi В соответствии со стандартами C и C++, да, семантически глобальные идентификаторы с ведущими символами подчеркивания зарезервированы. Однако они являются синтаксически допустимыми идентификаторами, и компилятор не помешает вам назвать функцию _Foo, хотя при этом вы полагаетесь на нестандартные детали реализации и, таким образом, рискуете, что ваш код будет нарушен будущими версиями реализации языка / стандартной библиотеки. /ОПЕРАЦИОННЫЕ СИСТЕМЫ.

BenW 16.06.2020 18:15

@BenW: TTBOMK, стандарт C++ просто говорит, что глобальные идентификаторы, начинающиеся с символа подчеркивания, недопустимы, без какого-либо различия между синтаксисом и семантикой. (Также любые идентификаторы, начинающиеся с символа подчеркивания, за которым следует заглавная буква, и идентификаторы с двумя последовательными символами подчеркивания.)

sbi 12.07.2020 00:14

От MSDN:

Use of two sequential underscore characters ( __ ) at the beginning of an identifier, or a single leading underscore followed by a capital letter, is reserved for C++ implementations in all scopes. You should avoid using one leading underscore followed by a lowercase letter for names with file scope because of possible conflicts with current or future reserved identifiers.

Это означает, что вы можете использовать одиночный символ подчеркивания в качестве префикса переменной-члена, если за ним следует строчная буква.

Очевидно, это взято из раздела 17.4.3.1.2 стандарта C++, но я не могу найти исходный источник полного стандарта в Интернете.

См. Также этот вопрос.

Я нашел похожий текст в n3092.pdf (черновик стандарта C++ 0x) в разделе: «17.6.3.3.2 Глобальные имена»

paercebal 27.06.2011 23:49

Интересно, что это, кажется, единственный ответ, который дает прямой и лаконичный ответ на вопрос.

hyde 03.10.2014 20:08

@hyde: На самом деле это не так, поскольку он пропускает правило, чтобы не иметь никаких идентификаторов с ведущим подчеркиванием в глобальном пространстве имен. См. Ответ Роджера. Я бы очень осторожно относился к ссылкам на документы MS VC как на авторитетные источники по стандарту C++.

sbi 09.07.2015 16:37

@sbi В этом ответе я имел в виду "вы можете использовать одиночный символ подчеркивания в качестве префикса переменной-члена, если за ним следует строчная буква", который отвечает на вопрос по тексту вопроса прямо и кратко, не утопая в стене текста.

hyde 10.07.2015 09:53

Во-первых, я до сих пор считаю неудачей отсутствие каких-либо намеков на то, что то же правило не применяется к глобальному пространству имен. Что еще хуже, так это то, что соседние символы подчеркивания запрещены не только в начале, но и в везде в идентификаторе. Таким образом, этот ответ не просто пропускает факт, но фактически делает по крайней мере одно явно неверное утверждение. Как я уже сказал, ссылаться на документы MSVC - это то, чего я бы не стал делать, если только вопрос не касается исключительно VC.

sbi 12.07.2015 21:48

@sbi: Правило внутреннего двойного подчеркивания было разработано, чтобы зарезервировать такие идентификаторы для имен с измененным типом, но я думаю, что имена с двойным подчеркиванием можно было бы приспособить, сказав, что любые вхождения __, сгенерированные искажением на основе типов, будут __x , а затем заявив, что любые вхождения __ в указанном имени будут заменены на __y перед таким искажением.

supercat 17.08.2016 17:29

А как насчет одного подчеркивания как полного имени переменной-члена?

PSkocik 22.12.2016 01:08

@sbi Есть ирония в том, что VC соответствует стандарту ISO C++, который также резервирует имена с одним подчеркиванием, одновременно переименовывая некоторые функции posix, например _dup () вместо dup ()

Swift - Friday Pie 02.02.2017 16:35
Ответ принят как подходящий

Правила (которые не изменились в C++ 11):

  • Зарезервировано в любой области, в том числе для использования в качестве макроса выполнение:
    • идентификаторы, начинающиеся с символа подчеркивания, за которым сразу следует заглавная буква
    • идентификаторы, содержащие соседние символы подчеркивания (или "двойное подчеркивание")
  • Зарезервировано в глобальном пространстве имен:
    • идентификаторы, начинающиеся с подчеркивания
  • Кроме того, все в пространстве имен std зарезервировано. (Тем не менее, вам разрешено добавлять специализации шаблонов.)

Из стандарта C++ 2003:

17.4.3.1.2 Global names [lib.global.names]

Certain sets of names and function signatures are always reserved to the implementation:

  • Each name that contains a double underscore (__) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use.
  • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.165

165) Such names are also reserved in namespace ::std (17.4.3.1).

Поскольку C++ основан на стандарте C (1.1 / 2, C++ 03), а C99 является нормативной ссылкой (1.2 / 1, C++ 03), они также применяются из стандарта C 1999 года:

7.1.3 Reserved identifiers

Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers.

  • All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
  • All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
  • Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included; unless explicitly stated otherwise (see 7.1.4).
  • All identifiers with external linkage in any of the following subclauses (including the future library directions) are always reserved for use as identifiers with external linkage.154
  • Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included.

No other identifiers are reserved. If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.

If the program removes (with #undef) any macro definition of an identifier in the first group listed above, the behavior is undefined.

154) The list of reserved identifiers with external linkage includes errno, math_errhandling, setjmp, and va_end.

Могут применяться другие ограничения. Например, стандарт POSIX резервирует множество идентификаторов, которые могут отображаться в обычном коде:

  • Имена, начинающиеся с заглавной буквы E, следует за цифрой или заглавной буквой:
    • может использоваться для дополнительных названий кодов ошибок.
  • Имена, начинающиеся с is или to, за которыми следует строчная буква
    • может использоваться для дополнительных функций проверки символов и преобразования.
  • Имена, начинающиеся с LC_, за которыми следует заглавная буква
    • может использоваться для дополнительных макросов, определяющих атрибуты локали.
  • Имена всех существующих математических функций с суффиксами f или l зарезервированы.
    • для соответствующих функций, которые работают с аргументами типа float и long double соответственно.
  • Имена, начинающиеся с SIG, за которыми следует заглавная буква, зарезервированы.
    • для дополнительных имен сигналов.
  • Имена, начинающиеся с SIG_, за которыми следует заглавная буква, зарезервированы.
    • для дополнительных сигнальных воздействий.
  • Имена, начинающиеся с str, mem или wcs, за которыми следует строчная буква, зарезервированы.
    • для дополнительных функций строк и массивов.
  • Имена, начинающиеся с PRI или SCN, за которыми следует любая строчная буква или X, зарезервированы.
    • для дополнительных макросов спецификатора формата
  • Имена, заканчивающиеся на _t, зарезервированы.
    • для дополнительных имен типов.

Хотя использование этих имен в ваших собственных целях прямо сейчас может не вызвать проблем, они все же повышают вероятность конфликта с будущими версиями этого стандарта.


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

После исследования этой статьи я больше не заканчиваю свои идентификаторы на _t. поскольку это зарезервировано стандартом POSIX.

Правило о любом идентификаторе, заканчивающемся на _t, меня очень удивило. Я думаю, что это стандарт POSIX (пока не уверен), требующий разъяснений и официальных глав и стихов. Это из Руководство GNU libtool, перечисляющего зарезервированные имена.

CesarB предоставил следующую ссылку на зарезервированные символы POSIX 2004 и отмечает, что «там можно найти многие другие зарезервированные префиксы и суффиксы ...». В Здесь определены зарезервированные символы POSIX 2008. Ограничения несколько более тонкие, чем указанные выше.

Просто примечание - за исключением нумерации, то, что Мартин процитировал из черновика стандарта, в точности совпадает со стандартом C++ 03 (17.4.3.1.2).

Michael Burr 23.10.2008 12:09

В вашем резюме не говорится того же, что и в цитате из Стандарта.

fizzer 23.10.2008 15:22

Имена Глобальный отличаются от "любого идентификатора

Adam Mitz 23.10.2008 17:07

@Adam Mitz: Глобальные имена также охватывают МАКРОСЫ. Что превратит ваши идентификаторы в кашу. Это то, что я пытался передать.

Martin York 23.10.2008 17:31

Вот официальная глава и стих, пожалуйста, добавьте к своему уже отличному ответу: opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.h‌ tml (и обратите внимание, что там можно найти множество других зарезервированных префиксов и суффиксов, которые вы не упомянули).

CesarB 24.10.2008 04:33

Стандарт C++ не «импортирует» C, не так ли? Насколько мне известно, они импортируют определенные заголовки, но не язык в целом или правила именования. Но да, этот тоже меня удивил. Но поскольку это C, он может применяться только к глобальным ns. Должно быть безопасно использовать _t внутри классов, когда я его читал

jalf 06.04.2009 20:16

@jalf: Стандарт C++ определяется в терминах стандарта C. По сути, он говорит, что C++ - это C с этими отличиями и дополнениями.

Martin York 07.04.2009 10:26

Мартин, в ответ вы говорите: «По крайней мере, это означает, что они не являются макросами ...», что я читал как «глобальные имена не являются макросами», что я также считаю, что это не так. макросы не являются членами :: и, следовательно, не являются глобальными. но в комментарии вы говорите, что «глобальные имена также охватывают МАКРОСЫ».

Johannes Schaub - litb 10.04.2009 21:09

каково ваше окончательное мнение по этому поводу? Я видел, как вы добавили это в ответ после того, как оставили свой комментарий. Итак, вы того же мнения, что и я, о том, что макросы не являются глобальными именами?

Johannes Schaub - litb 10.04.2009 21:10

Где в стандарте C++ проводится различие между вещами, зарезервированными «для компилятора» и «зарезервированными для ОС и библиотек», пожалуйста? Я видел, где зарезервированы имена для реализации, но не где указывается какое-либо различие между «компилятором», «ОС» и «библиотеками» как компонентами реализации.

Steve Jessop 13.06.2009 01:14

Стандарт C++ не «импортирует» стандарт C. Это использованная литература Стандарт C. Во введении к библиотеке C++ говорится: «Библиотека также предоставляет возможности стандартной библиотеки C». Это достигается путем включения заголовков стандартной библиотеки C с соответствующими изменениями, но не путем ее «импорта». Стандарт C++ имеет собственный набор правил, описывающих зарезервированные имена. Если имя, зарезервированное в C, должно быть зарезервировано в C++, это место, где можно сказать это. Но в стандарте C++ об этом не говорится. Поэтому я не верю, что вещи, зарезервированные в C, зарезервированы в C++, но я вполне могу ошибаться.

Johannes Schaub - litb 20.09.2009 05:34

Вот что я обнаружил о проблеме «_t»: n1256 (C99 TC3) говорит: «Имена Typedef, начинающиеся с int или uint и заканчивающиеся на _t» зарезервированы. Я думаю, что это все еще позволяет использовать такие имена, как "foo_t", но я думаю, что они затем зарезервированы POSIX.

Johannes Schaub - litb 20.09.2009 05:39

Из стандарта C++ 1.1. <quote> C++ - это язык программирования общего назначения, основанный на языке программирования C, как описано в ISO / IEC 9899: 1990 Языки программирования - C (1.2). В дополнение к возможностям, предоставляемым C, C++ предоставляет дополнительные типы данных </quote>. Я считаю, что все, что зарезервировано в C, также зарезервировано в C++, если иное явно не указано.

Martin York 20.09.2009 06:04

Как отмечалось в основной статье, суффикс _t зарезервирован только стандартом POSIX, а не стандартом C.

Martin York 20.09.2009 22:42

Значит, «толерантность» зарезервирована POSIX, поскольку начинается с «до» + строчная буква? Бьюсь об заклад, это правило нарушает большое количество кода!

Sjoerd 12.08.2010 02:35

@Sjoerd: Наверное. Хотя я уверен, что у вас все будет хорошо, если lerance не станет настоящим глаголом, который можно применять к персонажам. Также обратите внимание, что он зарезервирован только в глобальной области (C) _или стандартном пространстве имен (C++), поэтому вы можете иметь функциональные переменные с этим именем, не нарушая правила.

Martin York 12.08.2010 02:40

@ReubenMorais: Нет. Прочтите документацию по Posix.

Martin York 03.11.2012 02:36

GNU getopt_long() нарушает все правила: он определяет макросы no_argument, required_argument и optional_argument.

Maxim Egorushkin 21.02.2013 22:35

@MaximYegorushkin: Никаких правил не нарушено. Эти идентификаторы зарезервированы для реализации. getopt_long () является частью реализации компиляторов и стандартных библиотек GNU.

Martin York 22.02.2013 03:20

@LokiAstari, "Стандарт C++ определяется в терминах стандарта C. По сути, он говорит, что C++ - это C с этими отличиями и дополнениями." Ерунда! C++ ссылается только на стандарт C в [basic.fundamental] и библиотеке. Если то, что вы говорите, правда, где C++ говорит, что _Bool и _Imaginary не существуют в C++? Язык C++ определяется явно, а не в терминах «правок» C, иначе стандарт мог бы быть намного короче!

Jonathan Wakely 29.08.2013 18:16

@JonathanWakely: Я имел в виду второй абзац стандарта: <quote> C++ - это язык программирования общего назначения основан на языке программирования C, как описано в ISO / IEC 9899: 1999 Языки программирования - C (далее - стандарт C). В дополнение к возможностям, предоставляемым C, C++ предоставляет дополнительные типы данных, классы, шаблоны, исключения, пространства имен, перегрузку операторов, перегрузку имен функций, ссылки, бесплатные операторы управления хранилищами и дополнительные возможности библиотеки. </quote>

Martin York 30.08.2013 00:08

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

Martin York 30.08.2013 00:10

@LokiAstari, это очень общее утверждение, описывающее объем языка, это не означает, что все, что есть в C, импортируется в C++. Язык C++ (не библиотека) точно определяется своим собственным стандартом, а не ссылкой на другой, за исключением одной ссылки в [basic.fundamental].

Jonathan Wakely 30.08.2013 14:42

@JonathanWakely: <quote> В дополнение к возможностям, предоставляемым C, C++ предоставляет дополнительные .... </quote>. Но вы также должны воспринимать комментарий в контексте обсуждения в целом. Мы говорим о «зарезервированных именах» или, в частности, о «подчеркивании». Таким образом, я пытался передать, что зарезервированные имена в C также зарезервированы в C++. litb не согласен с такой интерпретацией, и я знаю, что он очень внимательно читает стандарт. Но этот разговор разрешился больше года назад.

Martin York 30.08.2013 23:59

В C++ я вижу только [lex.name] и для глобальных имен [global.names]. Можете ли вы объяснить, как тот факт, что C++ основан на стандарте C, а C99 является нормативным справочником, позволяет применять правила C99 к C++. Благодарность

a.lasram 11.01.2014 06:14

см. [intro.refs] из стандарта, он описывает, что это значит. См. здесь, чтобы получить копию

Martin York 12.01.2014 21:05

@LokiAstari: Я думаю, что ваше утверждение неверно. Одна из возможностей языка C состоит в том, что вы можете использовать идентификаторы, зарезервированные для него не; поэтому, если мы собираемся считать буквально уместным, что C++ включает «возможности, предоставляемые C», тогда идентификаторы, зарезервированные C++, фактически должны быть (максимум) подмножество из тех, что зарезервированы C, а не суперсет. (Но на самом деле мы с вами оба знаем, что C++ зарезервировал некоторые идентификаторы, которых нет в C, поэтому, очевидно, выражение «средства, предоставляемые C» буквально релевантно.)

ruakh 31.03.2014 01:16

@ruakh: Выше привожу цитату из стандарта C. 7.1.3 Reserved identifiers. Пожалуйста, перечитайте.

Martin York 31.03.2014 02:19

@LokiAstari: Проблема в том, в чем был бы вопрос? «Оставляет ли C++ неопределенным все, что остается неопределенным в C?» слишком тенденциозен (я полагаю, вы не можете далеко уйти от который), тогда как «Все ли идентификаторы зарезервированы в C, также зарезервированы в C++?» будет закрыто как обман этого. Должен ли я просто процитировать раздел спецификации C++, который вы цитируете, и спросить, каковы его нормативные последствия?

ruakh 31.03.2014 04:51

Может быть полезно знать, что большинство зарезервированных символов POSIX зарезервированы только при включении соответствующего включаемого файла, т.е. "int stringptr" является "допустимым", пока вы не включите <string.h>.

Remember Monica 23.10.2014 20:55

@LokiAstari Я понимаю, что такие стандарты необходимы для C++. Но, например, в Java есть только несколько зарезервированных имен полей (например, serialVersionUID), и, конечно, никакие стандарты, такие как переменные, заканчивающиеся на _t, не зарезервированы, потому что язык был разработан таким образом, что все находится в пространстве имен. Вы хотите сказать, что любой язык, который может быть скомпилирован в машинный код на нескольких платформах, должен иметь эти зарезервированные стандарты имен переменных?

Andy 11.06.2015 21:14

Интересно, возникнет ли какая-либо проблема с указанием того, что конкретный префикс был зарезервирован для макросов, определенных в будущих языковых версиях, с условием, что реализации должны либо обрабатывать их в соответствии со стандартом C, либо оставлять их неопределенными. Это позволило бы коду, использующему определенные новые функции, работать со старыми компиляторами, определяя макросы для их эмуляции. Например, если __CPP_EITHER (x, y) принимает два выражения или утверждения и позволяет компилятору выбирать между ними произвольным образом (надеюсь, в зависимости от того, какие из них могут быть скомпилированы более эффективно), то ...

supercat 28.06.2016 22:05

... код, использующий эту директиву, может работать с существующими реализациями, просто #ifndef __CPP_EITHER / #define __CPP_EITHER(x,y) x / #endif, но реализация, которая понимает директиву, может использовать ее для улучшения генерации кода в тех случаях, когда она может сказать, что y будет более эффективным, чем x (в случаях там, где он не мог сказать, он мог просто использовать x).

supercat 28.06.2016 22:08

@Sjoerd примерно да. В нем говорится, что любая реализация может определить новую функцию ctype tofoo для любого идентификатора foo, начинающегося с буквы, включая lerance. Если это произойдет, и это вызовет конфликт с вашим собственным глобалом, ну, вас предупредили. Практическое влияние на ты невелико, но это дает POSIX и разработчикам передышку, чтобы добавлять вещи без бесконечных придирок.

hobbs 06.08.2016 08:45

Правила могут быть лучше обновлены, чтобы отразить тот факт, что правила зарезервированных имен перемещены из библиотеки (раздел 17) на базовый язык (раздел 2) в текущем рабочем проекте стандарта C++.

FrankHB 07.08.2016 19:31

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

user8991265 11.02.2019 18:01

Если эти правила нарушены, вызывает ли это неопределенное поведение?

Max Barraclough 17.11.2019 18:16

@MaxBarraclough Да. Что может означать, что ничего не происходит. См. Раздел 5.10 Идентификаторы. Пункт 3In addition, some identifiers are reserved for use by C++ implementations and **shall not be used otherwise**; no diagnostic is required.

Martin York 18.11.2019 11:04

@MaxBarraclough Здесь важный термин - Не должны. Если вы посмотрите на C++ Раздел 3 Термины и определенияFor the purposes of this document, the terms and definitions given in ISO/IEC 2382-1:1993, the terms, definitions, and symbols given in ISO 80000-2:2009, and the following apply., вы можете найти эти термины здесь: iso.org/obp/ui => требуется, чтобы не.

Martin York 18.11.2019 11:16

@MaxBarraclough Таким образом, если вы нарушите это условие, ваш код не соответствует требованиям. Если затем прочитать Раздел 4 Общие принципы пункт 2.3If a program contains a violation of a rule for which no diagnostic is required, this document places no requirement on implementations with respect to that program.

Martin York 18.11.2019 11:20

@MaxBarraclough И напоследок. Смотрим на Раздел 3.27 неопределенное поведениеbehavior for which this document imposes no requirements.

Martin York 18.11.2019 11:26

@MartinYork: Каковы требования к соответствующей программе на языке C? В каждой версии Стандарта, которую я видел, нарушение ограничения означало бы, что программа не соответствует строго, но реализациям разрешено документировать расширения, которые отказываются от ограничений, и программа, которая работает в такой реализации, будет соответствовать, даже если это нарушает ограничение.

supercat 08.01.2020 19:25

@supercat Я редко использую C, поэтому не знаю.

Martin York 09.01.2020 01:17

@MartinYork: Стандарт C++ определяет понятие производительности для программы или просто реализации? Мне кажется, я припоминаю, что в прологе говорится, что любая ссылка на то, что программы могут или не могут делать, предназначена исключительно для интерпретации в отношении требований к реализациям.

supercat 09.01.2020 02:42

@MartinYork: Это различие важно, потому что реализациям разрешено расширять язык таким образом, чтобы расширять диапазон программ, которые они могут эффективно обрабатывать, и такое расширение может включать программы, которые нарушают ограничения. Нарушение ограничения не делает программу несоответствующей (поскольку такой концепции нет), но вместо этого означает, что реализациям не нужно осмысленно обрабатывать программу, если они не хотят этого делать.

supercat 09.01.2020 02:44

@supercat Почему вы спрашиваете в комментариях (это не подходящее место для этого обсуждения). Похоже, вам стоит задать это как вопрос. Тогда люди со знаниями попытаются ответить.

Martin York 09.01.2020 04:00

Я не верю, что это прописано в стандарте, но всегда ли идентификатор с «тройным подчеркиванием» (___) считается имеющим двойное подчеркивание? Я ... верю, что должен? Но эмпирические данные с моей стороны показывают, что некоторые люди могут найти приемлемым тройное подчеркивание.

JohnFilleau 28.10.2020 22:50

Но на самом деле формулировка такова: Each identifier that contains a double underscore __ Если у вас тройка, она содержит двойную!

Martin York 29.10.2020 00:24

Правила, позволяющие избежать столкновения имен, содержатся как в стандарте C++ (см. Книгу Страуструпа), так и упоминаются гуру C++ (Саттер и т. д.).

Личное правило

Поскольку я не хотел заниматься случаями и хотел иметь простое правило, я разработал личный, которое одновременно является простым и правильным:

При именовании символа вы избежите столкновения с компилятором / ОС / стандартными библиотеками, если вы:

  • никогда не начинайте символ с подчеркивания
  • никогда не называйте символ с двумя подряд идущими знаками подчеркивания внутри.

Конечно, размещение вашего кода в уникальном пространстве имен тоже помогает избежать коллизий (но не защитит от злых макросов).

Некоторые примеры

(Я использую макросы, потому что они больше загрязняют код символов C / C++, но это может быть что угодно, от имени переменной до имени класса)

#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT

Выдержки из проекта C++ 0x

Из файла n3242.pdf (я ожидаю, что окончательный стандартный текст будет аналогичным):

17.6.3.3.2 Global names [global.names]

Certain sets of names and function signatures are always reserved to the implementation:

— Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use.

— Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

Но и:

17.6.3.3.5 User-defined literal suffixes [usrlit.suffix]

Literal suffix identifiers that do not start with an underscore are reserved for future standardization.

Это последнее предложение сбивает с толку, если вы не считаете, что имя, начинающееся с одного подчеркивания и сопровождаемое строчной буквой, будет ОК, если нет определено в глобальном пространстве имен ...

@Meysam: __WRONG_AGAIN__ содержит два последовательных символа подчеркивания (два в начале и два в конце), поэтому согласно стандарту это неверно.

paercebal 18.01.2012 17:49

@ BЈовић: WRONG__WRONG содержит два последовательных символа подчеркивания (два посередине), поэтому согласно стандарту это неверно.

paercebal 04.12.2013 21:30
размещение вашего кода в уникальном пространстве имен также помогает избежать столкновений: но этого все равно недостаточно, поскольку идентификатор может конфликтовать с ключевым словом независимо от области действия (например, __attribute__ для GCC).
Ruslan 06.09.2016 12:53

Почему возникает проблема наличия двух последовательных символов подчеркивания в центре в соответствии со стандартом? Определяемые пользователем буквальные суффиксы применяются к буквальным значениям, таким как 1234567L или 4.0f; IIRC это относится к http://en.cppreference.com/w/cpp/language/user_literal

Jason S 12.09.2017 19:42
Why is there any problem of having two consecutive underscores in the middle according to the standard? Потому что стандарт гласит, что они зарезервированы. Это не совет в хорошем или плохом стиле. Это решение из стандарта. Почему они так решили? Я полагаю, что первые компиляторы уже неформально использовали такие соглашения до стандартизации.
paercebal 13.09.2017 20:54

Мне не удалось найти предложение [global.names] или что-то подобное в текущем проекте стандарта (eel.is/c++draft). Вроде убрали.

Henri Menke 03.05.2018 14:16

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

CoffeeTableEspresso 16.05.2019 23:39

@CoffeeTableEspresso: я все еще не понимаю, почему любая реализация требует, чтобы имена исходного кода не содержали двойных подчеркиваний. Даже если существующая реализация экспортировала сами имена с двойным подчеркиванием и запретила их в исходном коде, такая реализация могла бы добавить поддержку таких имен без нарушения совместимости компоновщика с любыми существующими объектными файлами, например, указание, что любой запуск из N символов подчеркивания в имени исходного кода будет заменен на 2N + 1 подчеркивание в имени компоновщика.

supercat 08.01.2020 19:32

Что касается другой части вопроса, обычно в конец имени переменной ставится подчеркивание, чтобы не конфликтовать ни с чем внутренним.

Я делаю это даже внутри классов и пространств имен, потому что тогда мне нужно запомнить только одно правило (по сравнению с «в конце имени в глобальной области и в начале имени везде»).

Другие вопросы по теме