Что означает двойное подчеркивание (__const) в C? - PullRequest
46 голосов
/ 19 сентября 2009
extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)
 __THROW;

Я нашел приведенное выше определение функции в /usr/include/netinet/ether.h на коробке с Linux.

Может кто-нибудь объяснить, что означают двойные подчеркивания перед const (ключевое слово), addr (идентификатор) и, наконец, __THROW.

Ответы [ 4 ]

68 голосов
/ 19 сентября 2009

В 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 ++, как упомянуто в верхней части этого ответа.

19 голосов
/ 19 сентября 2009

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

Идея состоит в том, что вам не разрешено использовать любые имена, начинающиеся с __, поэтому реализация может использовать их в местах, таких как расширения макросов, или в именах расширений синтаксиса (например, __gcnew не является частью C ++, но Microsoft может добавить его в C ++ / CLI, уверенный в том, что ни один из существующих кодов не должен содержать что-то вроде int __gcnew;, которое прекратит компиляцию).

Чтобы выяснить, что означают эти конкретные расширения, то есть __const, вам нужно обратиться к документации для вашего конкретного компилятора / платформы. В этом конкретном случае вам, вероятно, следует рассмотреть прототип в документации (например, http://www.kernel.org/doc/man-pages/online/pages/man3/ether_aton.3.html) как интерфейс функции и игнорировать декорации __const и __THROW, которые появляются в фактическом заголовке.

3 голосов
/ 19 сентября 2009

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

2 голосов
/ 19 сентября 2009

Подчеркивание в __const означает, что это ключевое слово является расширением компилятора и его использование не переносимо (ключевое слово const было добавлено в C в более поздней редакции, я думаю, 89). __THROW также является своего рода расширением, я предполагаю, что оно определено для некоторого __attribute __ (что-то), если используется gcc, но я не уверен в этом и слишком ленив для проверки. __Addr может означать все, что хотел программист, это просто имя.

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