Что означает "#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
, ты получишь:
- доступ ко множеству нестандартных функций расширения GNU/Linux
- доступ к традиционным функциям, которые были исключены из стандарта POSIX (часто по уважительной причине, например, замена на более совершенные альтернативы или привязка к конкретным устаревшим реализациям)
- доступ к низкоуровневым функциям, которые не могут быть переносимыми, но которые иногда требуются для реализации системных утилит, таких как
mount
,ifconfig
, так далее. - неправильное поведение для многих функций, определенных 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
--- который я получил в зависимости от того, где я установил точку останова, иногда после тысяч инструкций. Потому что я не отодвинул указатель инструкции...