Что значит "зарезервировано для любого использования"?

Примечание:c вопрос, хотя я добавил c++ в случае, если какой-либо эксперт c++ может предоставить обоснование или историческую причину, почему C++ использует другую формулировку, чем C.


в спецификации стандартной библиотеки C у нас есть этот нормативный текст, C17 7.1.3 зарезервированные идентификаторы (акцент мой):

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

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

Не " зарезервировано для любого используйте " mean зарезервировано для кто-нибудь кроме будущих расширений самого языка C? Это означает, что реализация не разрешено использовать их.

в то время как вторая фраза выше, касающаяся одного ведущего подчеркивания, кажется, направлена на реализацию?

В общем, стандарт C написан таким образом, что ожидает, что поставщики компиляторов / разработчики библиотек будут типичным читателем - не столько приложение программисты.

Примечательно, что C++ имеет совсем другую формулировку:

  • каждое имя, содержащее двойное подчеркивание (__) или начинается с подчеркивания, за которым следует заглавная буква (2.11) зарезервировано для реализации для любого использования.

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

это возможно путаница между C и C++ и языки здесь разные?

5 ответов


в стандарте C значение термина "зарезервировано" определяется пунктом 7.1.3p2, непосредственно под списком пуль, который вы цитируете:

другие идентификаторы не зарезервированы. Если программа объявляет или определяет идентификатор в контексте, в котором он зарезервирован (кроме как разрешено 7.1.4), или определяет зарезервированный идентификатор как имя макроса, поведение не определено.

акцент мой: зарезервированные идентификаторы устанавливают ограничение на программа, а не реализации. Таким образом, общая интерпретация – зарезервированные идентификаторы могут использоваться реализацией для любых целей – верна для C.

Я не поспевал за стандартом C++ и больше не чувствую себя квалифицированным для его интерпретации.


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

строго соответствующая программа должна использовать только те возможности языка и библиотеки указанный в настоящем международном Норматив....Соответствие размещенная реализация принимает любую строго соответствующую программу.

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

стандарт продолжается, однако:

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

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

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

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

стандарт C++ работает аналогичным образом, хотя он немного более явный о Гамбите:

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

Я подозреваю, что разница в формулировках сводится к стандарту C++, просто более ясному о том, как расширения должны работать. Тем не менее, ничего в C стандарт запрещает реализации делать то же самое. (И мы все в основном игнорируем требование, чтобы компилятор предупреждал вас каждый раз, когда вы используете __declspec.)


Что касается разницы в формулировках в C и c++, я размещаю свое собственное небольшое исследование здесь в качестве ссылки:

  • в начале K&R C 1-е издание этот текст:

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

  • K&R 2nd edition добавлено приложение B, которое обращается стандартная библиотека, где мы можем читать

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

  • ранние проекты ANSI C, а также " C90 " ISO 9899:1990 имеют тот же текст, что и в текущем стандарте ISO.

  • однако самые ранние проекты C++ имеют другой текст, как отмечает @hvd, возможно, уточнение стандарта C. От черновик: 20 сентября 1994:

    17.3.3.1.2 глобальные имена
    ...
    Каждое имя, начинающееся с символа подчеркивания и прописной буквы или другого символа подчеркивания (2.8) , зарезервировано для реализации для любого использования

таким образом, по-видимому, формулировка "зарезервирована для любого использования" была изобретена комитетом ANSI / ISO C90, тогда как C++ комитет несколько лет спустя использовал более четкие формулировки, похожие на то, что в pre-стандартную книгу К&Р.


обоснование C99 V5.10 говорит это ниже 7.1.3:

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

Это делает намерение комитета совершенно ясным: "зарезервировано для любого использования "означает"зарезервировано для исполнителя".


также следует отметить, что нынешний стандарт C имеет следующий нормативный текст в другом месте, в 6.2.5:

там также может быть реализации расширенной подписал целочисленные типы. 38)

где информативное Примечание 38 ноги говорит:

38) ключевые слова, определенные реализацией, должны иметь форму идентификатора, зарезервированного для любого использования как описана в п. 7.1.3.


C имеет несколько контекстов, в которых символ может иметь такое определение:

  • пространство имен макрос
  • пространство формальных имен аргументов для макроса (это пространство специфично для каждого функционального макроса),
  • пространство обычных идентификаторов,
  • пространство имен тегов
  • пространство меток (это пространство специфично для каждой функции) и
  • пространство членов структуры / объединения (это пространство специфично для каждой структуры / объединения).

что "зарезервировано для любого использования" означает, что пользовательский код в совместимой программе не может использовать1 символы, начинающиеся с подчеркивания, за которым следует заглавная буква или другое подчеркивание в любом из вышеуказанных контекстов. Сравните с идентификаторами, начинающимися с одного символа подчеркивания, за которым следует строчное число или цифра. Это относится ко второму классу идентификаторов, которые начинаются с подчеркивания. Код пользователя can можно использовать эти идентификаторы как имена аргументов макросов, как метки или как имена членов структуры/объединения.

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


1стандарт не совсем означает "не может использовать". Стандарт поощряет программное использование небольшого числа имен, начинающихся с двойного подчеркивания. Например, для определения , __FILE__, __LINE__ и __func__. Версия стандарта 2011 года даже дает пример предположительно совместимой программы, которая ссылается __func__.


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

#ifdef __ACME_COMPILER
#define near __near
#else
#define near
#endif

int near foo;

объявить идентификатор foo С помощью __near квалификатор, если код обрабатывается в компиляторе Acme (который предположительно поддерживает такую вещь), но также совместимость с другими компиляторами, которые не будут требовать или извлекать выгоду из использования такой директивы. Ничто не запрещает соответствующей реализации определять __ACME_COMPILER и интерпретации __near означает "запуск ядерных ракет", но качественная реализация не должна выходить из своего пути, чтобы сломать код, как указано выше. Если реализация не знает, что __ACME_COMPILER предполагается, что это означает, что обращение с ним как с любым другим неизвестным идентификатором позволит ему поддерживать полезные конструкции, такие как выше.