Читая Что означает / означает -D_XOPEN_SOURCE?, я понять, как использовать макросы тестирования функций.

Но я все еще не понимаю, зачем нам это нужно, я имею в виду, можем ли мы просто включить все доступные функции? Затем документ пишет так: эта функция доступна только в Mac / BSD, эта функция доступна только в Linux, если вы ее используете, ваша программа может работать только в этой системе.

Так зачем вообще нам нужен макрос для тестирования функций?

5
scriptboy 5 Июл 2021 в 20:08

3 ответа

Лучший ответ

Зачем нам это нужно, я имею в виду, можем ли мы просто включить все доступные функции?

Представьте, что какая-то компания написала отличный суперпортативный код примерно следующего вида:

#include <stdlib.h>
struct someone_s { char name[20]; };

/// @brief grants Plant To someone
int grantpt(int plant_no, struct someone_s someone) {
   // some super plant granting algorithm here
   return 0;
}

int main() {
   // some program here
   struct someone_s kamil = { "Kamil" };
   return grantpt(20, kamil);
}

Эта программа полностью исправна, и все работает нормально, и эта программа очень совместима с C, поэтому ее следует переносить куда угодно. А теперь представьте на мгновение, что _XOPEN_SOURCE не существует! Клиент получает исходные коды этой программы и пытается скомпилировать и запустить ее на своем новейшем Unix-компьютере с сертифицированным компилятором C в сертифицированной системе POSIX, и он получает ошибку, которую эта компания должна исправить и за которую, в свою очередь, должна заплатить:

/tmp/1.c:7:9: error: conflicting types for ‘grantpt’; have ‘int(struct someone_s,  int)’
    7 |     int grantpt(struct someone_s someone, int plant_no) {
      |         ^~~~~~~
In file included from /tmp/1.c:2:
/usr/include/stdlib.h:977:12: note: previous declaration of ‘grantpt’ with type ‘int(int)’
  977 | extern int grantpt (int __fd) __THROW;
      |            ^~~~~~~

Похоже, что в POSIX выбрано совершенно случайное имя функции - grantpt ( ).

При добавлении новых символов, которых нет в зарезервированном пространстве, Стандарты, подобные POSIX, не могут просто «добавлять их» и ожидать, что мир не будет протестовать - противоречивые определения могут и будут нарушать действующие программы. Чтобы решить эту проблему, были введены feature_test_macros. Когда программа выполняет #define _XOPEN_SOURCE 500, это означает, что она подготовлена ​​для стандарта POSIX и нет конфликтов между кодом и символами, введенными POSIX в этой версии.

Макросы тестирования функций - это не просто «моя программа хочет использовать эти функции», это, что наиболее важно, «моя программа не конфликтует с этими функциями», что гораздо важнее, чтобы существующие программы продолжали работать.

4
KamilCuk 5 Июл 2021 в 18:44

Теоретическая причина, по которой у нас есть макросы выбора функций в C, состоит в том, чтобы избавить вас от библиотеки C. Предположим, гипотетически вы хотите использовать имя getline для функции в вашей программе. Стандарт C говорит, что вы можете это сделать. Но некоторые операционные системы предоставляют функцию библиотеки C под названием getline в качестве расширения. Его объявление, вероятно, будет противоречить вашему определению. С помощью макросов выбора функций вы, в принципе, можете запретить этим ОС stdio.h объявлять свои getline, чтобы вы могли использовать свою.

На практике эти макросы слишком грубые, чтобы быть полезными, и используются только те, которые означают «дайте мне все, что у вас есть», и люди делают именно то, что вы предполагаете, в документации.

В новых языках программирования (Ada, C ++, Modula-2 и т. Д.) Есть концепция «модулей» (иногда также называемых «пространствами имен»), которые позволяют программисту дать точный список того, что они хотят от библиотеки времени выполнения; это работает намного лучше.

3
zwol 5 Июл 2021 в 17:49

Зачем нам нужны макросы для тестирования функций?

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

Одним из примеров является набор функций *_s, например strcpy_s:
errno_t strcpy_s(char *restrict dest, rsize_t destsz, const char *restrict src);

// put this first to signal that you actually want the LIB_EXT1 functions
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>

Затем в вашем коде:

#ifdef __STDC_LIB_EXT1__
    errno_t err = strcpy_s(...);  // The implementation supports it so you can use it
#else
    // Not supported, use an alternative, like your own implementation
    // or let it fail to compile.
#fi

мы можем просто включить все доступные функции?

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

Точно так же реализация связывается не со всеми доступными библиотеками, а только с самыми основными. Вы должны сказать то, что вам нужно.

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

#define _XOPEN_SOURCE     700
#define __STDC_LIB_EXT1__ 1
...

Но, как вы видите с _XOPEN_SOURCE, существуют разные выпуски, и вы не можете включить их все одновременно, вам нужно выбрать один.

2
Ted Lyngmo 5 Июл 2021 в 17:52