Что означает двойное подчеркивание ( __const) в C?
-
11-09-2019 - |
Вопрос
extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)
__THROW;
Я нашел вышеупомянутое определение функции в /usr/include/netinet/ether.h на коробке Linux.
Кто-нибудь может объяснить, что означают двойные подчеркивания перед const (ключевое слово), addr (идентификатор) и, наконец, __THROW.
Решение
В C символы, начинающиеся с символа подчеркивания, за которым следует либо заглавная буква, либо другое подчеркивание, зарезервированы для реализации.Вы, как пользователь C, не должны создавать никаких символов, которые начинаются с зарезервированных последовательностей.В C ++ ограничение более строгое;вы, пользователь, не можете создавать символ, содержащий двойное подчеркивание.
Данный:
extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)
__THROW;
В __const
обозначения существуют для того, чтобы учесть возможность (несколько маловероятную) того, что компилятор, с которым используется этот код, поддерживает обозначения прототипов, но не имеет правильного понимания стандартного ключевого слова C89 const
.В autoconf
макросы все еще могут проверять, имеет ли компилятор рабочую поддержку для const
;этот код может быть использован со сломанным компилятором, который не имеет такой поддержки.
Использование __hostname
и __addr
это мера защиты для вас, пользователя заголовка.Если вы скомпилируете с помощью GCC и -Wshadow
в противном случае компилятор предупредит вас, когда какие-либо локальные переменные затеняют глобальную переменную.Если функция, используемая просто hostname
вместо того , чтобы __hostname
, и если бы у вас была вызванная функция hostname()
, была бы слежка.При использовании имен, зарезервированных для реализации, не возникает конфликта с вашим законным кодом.
Использование __THROW
означает, что код может, при некоторых обстоятельствах, быть объявлен с какой-то "спецификацией броска".Это не стандартный C;это больше похоже на C ++.Но код может использоваться с компилятором C до тех пор, пока один из заголовков (или сам компилятор) определяет __THROW
к пустому или к какому-либо специфичному для компилятора расширению стандартного синтаксиса C.
Раздел 7.1.3 стандарта C (ISO 9899:1999) гласит:
7.1.3 Зарезервированные идентификаторы
Каждый заголовок объявляет или определяет все идентификаторы, перечисленные в соответствующем подразделе, и необязательно объявляет или определяет идентификаторы, перечисленные в связанных с ним будущих библиотечных указаниях подраздел и идентификаторы, которые всегда зарезервированы либо для любого использования, либо для использования в качестве файла идентификаторы области.
— Все идентификаторы, которые начинаются с подчеркивания и либо с заглавной буквы, либо с другой подчеркивание всегда зарезервировано для любого использования.
— Все идентификаторы, начинающиеся с подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с областью действия файла как в обычном пространстве, так и в пространстве имен тегов.
— Каждое имя макроса в любом из следующих подразделов (включая будущую библиотеку инструкции) зарезервировано для использования, как указано, если включен какой-либо из связанных с ним заголовков;если явно не указано иное (см. 7.1.4).
— Все идентификаторы с внешней привязкой в любом из следующих подразделов (включая будущие инструкции по библиотеке) всегда зарезервированы для использования в качестве идентификаторов с внешней привязкой .154)
— Каждый идентификатор с областью действия файла, указанный в любом из следующих подразделов (включая будущие инструкции по библиотеке), зарезервирован для использования в качестве имени макроса и в качестве идентификатора с область действия файла в том же пространстве имен, если включен какой-либо из связанных с ним заголовков.
Никакие другие идентификаторы не зарезервированы.Если программа объявляет или определяет идентификатор в контексте , в котором он зарезервирован (кроме того, что разрешено 7.1.4), или определяет зарезервированный идентификатор как имя макроса, поведение не определено.
Если программа удаляет (с
#undef
) любое макроопределение идентификатора в первой группе поведение, указанное выше, не определено.Сноска 154) Список зарезервированных идентификаторов с внешней привязкой включает
errno
,math_errhandling
,setjmp
, иva_end
.
Смотрите также Каковы правила использования символа подчеркивания в идентификаторе C ++;многие из одних и тех же правил применимы как к C, так и к C ++, хотя встроенное правило двойного подчеркивания действует только в C ++, как упомянуто в верхней части этого ответа.
Другие советы
Имена с двойным начальным подчеркиванием зарезервированы для использования реализацией.Это не обязательно означает, что они являются внутренними сами по себе, хотя часто так и есть.
Идея в том, что вам не разрешается использовать какие-либо имена, начинающиеся с __
, поэтому реализация может свободно использовать их в таких местах, как расширения макросов, или в названиях синтаксических расширений (например __gcnew
не является частью C ++, но Microsoft может добавить его в C ++ / CLI, уверенный, что ни один существующий код не должен содержать что-то вроде int __gcnew;
в нем это остановило бы компиляцию).
Чтобы выяснить, что означают эти конкретные расширения, т.е. __const
вам нужно будет ознакомиться с документацией для вашего конкретного компилятора / платформы.В этом конкретном случае вам, вероятно, следует рассмотреть прототип в документации (например http://www.kernel.org/doc/man-pages/online/pages/man3/ether_aton.3.html) быть интерфейсом функции и игнорировать __const
и __THROW
украшения, которые отображаются в самом заголовке.
По соглашению в некоторых библиотеках это указывает на то, что определенный символ предназначен для внутреннего использования и не предназначен для того, чтобы быть частью общедоступного API библиотеки.
Подчеркивание в __const означает, что это ключевое слово является расширением компилятора и его использование не является переносимым (ключевое слово const было добавлено в C в более поздней редакции, я думаю, 89).__THROW также является своего рода расширением, я предполагаю, что оно определяется для некоторого __атрибута__(чего-то), если используется gcc, но я не уверен в этом и слишком ленив, чтобы проверять.__addr может означать все, что хотел программист, это просто имя.