Имена идентификаторов C: Что идет с каким компилятором? - PullRequest
0 голосов
/ 30 января 2019

Я экспериментировал с extern и extern "C" немного, и случайно обнаружил опечатку в одном из идентификаторов - $ пробрался. Когда я скомпилировал код и получил ошибку неопределенного символаи в конце концов увидел, что вызвало это, это сделало меня любопытным, если бы это на самом деле компилировалосьИ угадайте, что - Clang на самом деле действительно скомпилировал это.

В соответствии с документацией, которую я читал ранее, правила для идентификаторов были в основном:

  • Нет двойного подчеркивания вначало - потому что они зарезервированы.
  • Нет ни одного символа подчеркивания и заглавной буквы - тоже зарезервировано.
  • Должен начинаться с буквы, не цифры.
  • Не долженпревышать 31 символ.
  • Может содержать a-z, A-Z или 0-9 и _.

Но это скомпилировано просто отлично - никаких предупреждений тоже не показывалось:

void __this$is$a$mess() {}
int main() { __this$is$a$mess(); }

При взгляде на него:

Ingwie@Ingwies-Macbook-Pro.local /tmp $ clang y.c
Ingwie@Ingwies-Macbook-Pro.local /tmp $ nm a.out
0000000100000f90 T ___this$is$a$mess
0000000100000000 T __mh_execute_header
0000000100000fa0 T _main
                 U dyld_stub_binder

Я очень четко вижу название символа.

Так почему же Clang разрешил мне это сделать, хотяпо стандартам ANSI не должно?Даже GCC 6, который я установил, не предупреждал об этом и не выдавал ошибку.

Какие компиляторы разрешат какие типы идентификаторов - и почему на самом деле?

Ответы [ 2 ]

0 голосов
/ 31 января 2019

В соответствии с документацией, которую я читал ранее, правила для идентификаторов были в основном:

  • В начале нет двойного подчеркивания - потому что они зарезервированы.
  • Нет одинарныхсимволы подчеркивания и верхнего регистра - тоже зарезервированы.

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

  • Должен начинаться с буквы, не цифры.

Буквы действительно нецифры, но не все цифры не являются буквами.Символ _ является ярким примером.

  • Не должен превышать 31 символ.

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

Некоторые реализации распознают более значимые символы, а некоторые даже неограниченное число.

  • Может содержать az, AZ или 0-9 и _.

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

Так почему же Clang разрешает мне это делать, хотя по стандартам ANSI этого не должно быть?Даже GCC 6, который я установил, не предупреждал об этом и не выдавал ошибку.

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

0 голосов
/ 30 января 2019

Правила в стандарте C 2018 для идентификаторов включают в себя:

  • В соответствии с 6.4.2.1 1, идентификатор представляет собой последовательность идентификатор-не-цифра и цифра символов, начиная с идентификатор без цифры .
  • идентификатор-номер равен _, a до z, A до Z, имя универсального символа или «другие символы, определяемые реализацией».
  • A цифра равно 09.
  • A имя-универсального символа равно \u, за которым следуют четыре шестнадцатеричные цифры или \U, за которыми следуют восемь шестнадцатеричных цифр, которые определяют Unicode Знаки.

Итак, если реализация допускает $, это допустимый символ для этой реализации.Вы можете использовать его, но он не может быть переносим на другие реализации.Стандарт C требует реализаций для принятия указанных символов, но он позволяет им принимать больше.Как правило, стандарт С следует рассматривать как открытое поле, а не огороженный сад: поведение определяется внутри поля, но вы не остановлены у барьера;вы можете пойти дальше, на свой страх и риск.

Правила, которым вас учили, были правилами того, что является переносимым, а не правилами того, что стандарт C требует, чтобы реализации ограничивали вас.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...