Что означает "#define _GNU_SOURCE"?

Сегодня я должен был использовать basename() функция и man 3 basename ( здесь) дал мне странное сообщение:

Заметки

Существует две разные версии basename () - версия POSIX, описанная выше, и версия GNU, после которой

#define _GNU_SOURCE
#include <string.h>

Мне интересно что это #define _GNU_SOURCE означает: это портит код, который я пишу с лицензией, связанной с GNU? Или это просто используется, чтобы сказать компилятору что-то вроде: "Ну, я знаю, этот набор функций не является POSIX, поэтому не переносим, ​​но я все равно хотел бы использовать его".

Если так, то почему бы не дать людям разные заголовки вместо того, чтобы определять какой-то непонятный макрос, чтобы получить одну реализацию функции или другую?

Что-то меня также беспокоит: как компилятор узнает, какую реализацию функции связать с исполняемым файлом? Использует ли это #define также?

У кого-нибудь есть советы, чтобы дать мне?

5 ответов

Решение

Определяющий _GNU_SOURCE не имеет ничего общего с лицензией и не имеет ничего общего с написанием (не) переносимого кода. Если вы определите _GNU_SOURCE, ты получишь:

  1. доступ ко множеству нестандартных функций расширения GNU/Linux
  2. доступ к традиционным функциям, которые были исключены из стандарта POSIX (часто по уважительной причине, например, замена на более совершенные альтернативы или привязка к конкретным устаревшим реализациям)
  3. доступ к низкоуровневым функциям, которые не могут быть переносимыми, но которые иногда требуются для реализации системных утилит, таких как mount, ifconfig, так далее.
  4. неправильное поведение для многих функций, определенных POSIX, когда люди GNU не согласились с комитетом по стандартам о том, как функции должны вести себя, и решили сделать свое дело.

Пока вы знаете об этих вещах, это не должно быть проблемой, чтобы определить _GNU_SOURCE, но вы должны избегать его определения и вместо этого определять _POSIX_C_SOURCE=200809L или же _XOPEN_SOURCE=700 по возможности, чтобы ваши программы были переносимы.

В частности, вещи из _GNU_SOURCE то, что вы никогда не должны использовать, #2 и #4 выше.

Для точной информации о том, что все включено _GNU_SOURCEДокументация может помочь.

Из документации GNU:

Макрос: _GNU_SOURCE

Если вы определите этот макрос, все будет включено: расширения ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X/Open, LFS и GNU. В случаях, когда POSIX.1 конфликтует с BSD, определения POSIX имеют приоритет.

Из справочной страницы Linux по макросам тестирования функций:

_GNU_SOURCE

Определение этого макроса (с любым значением) неявным образом определяет _ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE, _XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE со значением 200809L (200112L в версиях glibc версии 2000–150; gLibL 2000) до 2000; _XOPEN_SOURCE со значением 700 (600 в версиях glibc до 2.10; 500 в версиях glibc до 2.2). Кроме того, различные специфичные для GNU расширения также доступны.

Начиная с glibc 2.19, определение _GNU_SOURCE также имеет эффект неявного определения _DEFAULT_SOURCE. В версиях glibc до 2.20 определение _GNU_SOURCE также неявно определяло _BSD_SOURCE и _SVID_SOURCE.

Примечание: _GNU_SOURCE Перед включением заголовочных файлов необходимо определить их, чтобы соответствующие заголовки включали функции. Например:

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
...

_GNU_SOURCE можно также включить для каждой компиляции, используя -D флаг:

$ gcc -D_GNU_SOURCE file.c

(-D не является специфическим для _GNU_SOURCE но любой макрос можно определить таким образом).

Позвольте мне ответить еще на два момента:

Что-то меня также беспокоит: как компилятор узнает, какую реализацию функции связать с исполняемым файлом? Использует ли он также этот #define?

Общий подход заключается в условно #define идентификатор basename на разные имена, в зависимости от того, _GNU_SOURCE определено. Например:

#ifdef _GNU_SOURCE
# define basename __basename_gnu
#else
# define basename __basename_nongnu
#endif

Теперь библиотеке просто необходимо предоставить оба поведения под этими именами.

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

Часто один и тот же заголовок имел немного различное содержимое в разных версиях Unix, поэтому нет единого правильного содержимого, скажем, для <string.h> - Есть много стандартов ( xkcd). Существует целый набор макросов для выбора вашего любимого, так что если ваша программа ожидает один стандарт, библиотека будет соответствовать этому.

Из какого-то списка рассылки через Google:

Посмотрите на glibc include / features.h:

_GNU_SOURCE Все вышеперечисленное, а также расширения GNU.

Что означает, что это позволяет все это:

STRICT_ANSI, _ISOC99_SOURCE, _POSIX_SOURCE, _POSIX_C_SOURCE, _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED, _LARGEFILE_SOURCE, _LARGEFILE64_SOURCE, _FILE_OFFSUR_SO_S__SID = _BS

Так что это позволяет много компилировать флаги для GCC

почему бы не дать людям разные заголовки

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

Я искал преобразование номера сигнала в имя. я нашел strsignal(), в <string.h>. На странице руководства говорится:

      sigabbrev_np(), sigdescr_np():
       _GNU_SOURCE                              <<< not default
strsignal():
       From glibc 2.10 to 2.31:
           _POSIX_C_SOURCE >= 200809L           <<< default, cf. XOPEN2K8 below
       Before glibc 2.10:
           _GNU_SOURCE

Меня вообще никогда не интересовала эта часть. sigabbrev_np()не входит в «функции» по умолчанию. string.hпокажи покажи:

      #ifdef  __USE_XOPEN2K8
/* Return a string describing the meaning of the signal number in SIG.  */
extern char *strsignal (int __sig) __THROW;

# ifdef __USE_GNU
/* Return an abbreviation string for the signal number SIG.  */
extern const char *sigabbrev_np (int __sig) __THROW;
/* Return a string describing the meaning of the signal number in SIG,
   the result is not translated.  */
extern const char *sigdescr_np (int __sig) __THROW;
# endif

__USE_GNUможет/должно быть установлено через _GNU_SOURCE, при компиляции или в начале файла. Но это также «активирует» все другие подобные объявления ifdeffed во всех заголовках. (Если вы не определите-неопределить для каждого заголовка)

Итак, чтобы явно импортировать только одну (или другую) специальную функцию, я пока делаю так (копировать-вставить. Я оставил «THROW» и изменил «__sig»):

      #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
extern const char *sigabbrev_np(int sig) __THROW;  /* __USE_GNU / _GNU_SOURCE */
#include <errno.h>
#include <elf.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
...

В настоящее время sigabbrev_np(wstate >> 8)дает мне и т. д. без #define.

мне было трудно это понять 0x57fзначит нормально потому что 5является TRAP, но 0xb7fа также 0x77fнаходятся SEGVа также BUS--- который я получил в зависимости от того, где я установил точку останова, иногда после тысяч инструкций. Потому что я не отодвинул указатель инструкции...

Другие вопросы по тегам