Что означает двойное подчеркивание ( __const) в C?
extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)
__THROW;
Я нашел приведенное выше определение функции в /usr/include/netinet/ether.h на коробке Linux.
Может кто-нибудь объяснить, что означают двойные подчеркивания перед const (ключевое слово), addr (идентификатор) и, наконец, __THROW.
4 ответа
В 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 также является своего рода расширением, я предполагаю, что оно определено для некоторого __attribute __ (что-то), если используется gcc, но я не уверен в этом и слишком ленив для проверки. __Addr может означать все, что хотел программист, это просто имя.