Почему библиотеки и язык c определяют _name, а затем typedef или pound определяют _name name?

#c #syntax #macros

#c #синтаксис #макросы

Вопрос:

Кажется, что в библиотеках и языке C много бесполезных имен типов. Например, C имеет встроенный тип _Bool и в нем есть макрос stdbool.h , #define bool _Bool . Почему C просто не было bool встроено вместо _Bool ? Я нашел больше примеров в stdio.h и stdlib.h . Вот так:

 # define WEXITSTATUS(status)    __WEXITSTATUS (status)
# define WTERMSIG(status)   __WTERMSIG (status)
# define WSTOPSIG(status)   __WSTOPSIG (status)
# define WIFEXITED(status)  __WIFEXITED (status)
# define WIFSIGNALED(status)    __WIFSIGNALED (status)
# define WIFSTOPPED(status) __WIFSTOPPED (status)
# ifdef __WIFCONTINUED
#  define WIFCONTINUED(status)  __WIFCONTINUED (status)
# endif
  

Мой вопрос в том, зачем беспокоиться об объявлении функции __FUNCTIONNAME (arg) и затем #define FUNCTIONNAME(arg) __FUNCTIONNAME(arg) ? Почему бы просто не объявить FUNCTIONNAME(arg) для начала?

Другой пример в stdio.h :

 extern FILE *__stdinp;
extern FILE *__stdoutp;
extern FILE *__stderrp;
  

И позже:

 #define stdin __stdinp
#define stdout __stdoutp
#define stderr __stderrp
  

Если серьезно, то почему? Что плохого в том, чтобы просто определить их, а затем объявить их следующим образом:

 extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
  

Почему они просто не объявили функции без подчеркивания, и тогда эти макросы не понадобились бы?

Комментарии:

1. Имена с двойным подчеркиванием являются встроенными функциями, зависящими от конкретной реализации.

2. Я думаю, что bool материал предназначен для совместимости с различными историческими предложениями.

3. @Barmar Я уже видел это имя раньше на сайте, и я согласен, что операторы if без скобок сомнительны, но что вы подразумеваете под встроенными функциями, специфичными для конкретной реализации?

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

5. Не забывайте, что C восходит к началу 70-х годов. Проведите свое исследование.

Ответ №1:

Все дело в управлении пространством имен.

Имена, перед которыми стоят два символа подчеркивания или символ подчеркивания и заглавная буква, зарезервированы для реализации. Реализация может предоставлять их практически без разбора (ну, на самом деле не очень ясно, какие зарезервированные имена принадлежат компиляторам, а какие реализациям libc).

Такие имена, как WIFCONTINUED , с другой стороны, принадлежат пользователю (и <sys/wait.h> в POSIX), и stdlib.h не должны содержать их в POSIX.

GLIBC предоставляет их из stdlib.h только условно:

 #if (defined __USE_XOPEN || defined __USE_XOPEN2K8) amp;amp; !defined _SYS_WAIT_H
/* XPG requires a few symbols from <sys/wait.h> being defined.  */
# include <bits/waitflags.h>
# include <bits/waitstatus.h>

/* Define the macros <sys/wait.h> also would define this way.  */
# define WEXITSTATUS(status)    __WEXITSTATUS (status)
# define WTERMSIG(status)   __WTERMSIG (status)
# define WSTOPSIG(status)   __WSTOPSIG (status)
# define WIFEXITED(status)  __WIFEXITED (status)
# define WIFSIGNALED(status)    __WIFSIGNALED (status)
# define WIFSTOPPED(status) __WIFSTOPPED (status)
# ifdef __WIFCONTINUED
#  define WIFCONTINUED(status)  __WIFCONTINUED (status)
# endif
#endif  /* X/Open or XPG7 and <sys/wait.h> not included.  */
  

и это не включает их, #including <sys/wait.h> вероятно, потому, что <sys/wait.h> , вероятно, содержит другие материалы, которые не должны включаться, даже если условие для этого #if (запускаемое правильными макросами для проверки функций ) блока выполнено. … (запускаемый правильными макросами для проверки функций ).

При использовании с префиксом формы (определяется во внутреннем <bits/waitstatus.h> ), <sys/wait.h> можно затем повторно использовать одни и те же (идентично переопределить макросы не генерировать предупреждения) и все работает даже тогда, когда они оба #include д; А нет заголовка предоставляет больше не зарезервированными именами, чем требуется по действующим нормам (стандартам в использовании зависит от макросы тестирования свойств , с которой вы компилируете).

Gtk просто неправильный. Gtk не является реализацией libc, и поэтому он не имеет права использовать эти зарезервированные имена.

Комментарии:

1. Я ожидаю, что команда Gtk приняла решение «мы являемся частью реализации» и намеренно используем имена, зарезервированные для «реализации», ограничивая возможность повреждения, используя _Gtk в качестве префикса (таким образом, компилятор должен был бы сознательно решить использовать тот же префикс для некоторого имени, если это действительно должно было вызвать у команды Gtk какие-либо проблемы).

2. на самом деле не очень ясно, какие зарезервированные имена принадлежат компиляторам, а какие реализациям libc Что касается стандарта C, я не думаю, что есть большая разница. Все, что не является частью пользовательского кода или сторонних библиотек, является «реализацией».

3. @Barmar К сожалению. На практике, однако, должно быть различие, поскольку библиотеки и компиляторы обычно предоставляются разными поставщиками. Отсутствие этого различия также не просто теоретическая досада. Я полагаю, что был по крайней мере один случай, когда две общие реализации libc и компилятора (glibc и clang?) произошла ошибка, и из-за этого пришлось переименовать один из его зарезервированных идентификаторов.

4. Что касается программиста, использующего их, то здесь нет различия. Для выполнения того, что вы хотите, стандарту потребуется несколько уровней пространства имен для компилятора, стандартной библиотеки и конечного программиста. И им также может потребоваться другой уровень для «популярных» библиотек, таких как POSIX API и Gtk. Чем это заканчивается?