Самый стандартный способ выбрать имя функции в зависимости от платформы?

В настоящее время я использую функцию popen в коде, который компилируется двумя компиляторами: MS Visual Studio и gcc (в Linux). Возможно, я захочу добавить gcc (на MinGW) позже.

Функция называется popen для gcc, но _popen для MSVS, поэтому я добавил в свой исходный код следующее:

#ifdef _MSC_VER
#define popen _popen
#define pclose _pclose
#endif

Это работает, но хотелось бы понять, существует ли стандартное решение таких проблем (вспоминаю аналогичный случай с stricmp/strcasecmp). В частности, я хотел бы понять следующее:

  1. Является ли _MSC_VER правильным флагом, от которого можно зависеть? Я выбрал его, потому что у меня сложилось впечатление, что среда Linux «более стандартна».
  2. Если я помещу эти #define в какой-то заголовочный файл, важно ли я #include до или после stdio.h (в случае popen)?
  3. Если _popen определяется как макрос, есть ли шанс, что мой #define не сработает? Должен ли я вместо этого использовать «новый» токен, такой как my_popen, по той или иной причине?
  4. Кто-то уже сделал эту работу для меня и сделал хороший файл «заголовка переносимости», который я могу использовать?
  5. Что-нибудь еще, о чем я должен знать?

person anatolyg    schedule 30.01.2011    source источник


Ответы (4)


То, как вы это делаете, нормально (с #ifdef и т. д.), но макрос, который вы тестируете, - нет. popen зависит от вашей операционной системы, а не от вашего компилятора.

Я бы пошел на что-то вроде

#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 2)
/* system has popen as expected */
#elif defined(YOUR_MACRO_TO DETECT_YOUR_OS)
# define popen _popen
# define pclose _pclose
#elif defined(YOUR_MACRO_TO DETECT_ANOTHER_ONE)
# define popen _pOpenOrSo
# define pclose _pclos
#else
# error "no popen, we don't know what to do"
#endif
person Jens Gustedt    schedule 30.01.2011

  1. Лучше проверить определение для Windows (возможно, _WIN32), потому что у mingw его тоже не будет. popen() стандартизирован (это часть Единой спецификации UNIX® v2)
  2. Нет; пока макрос определен до его первого использования, не имеет значения, определен ли _popen() позже.
  3. Нет; то, что у вас есть, прекрасно, даже если _popen является макросом.
  4. Это делалось много раз, но я не знаю версии со свободной лицензией, которую вы могли бы использовать.
person Phil Willoughby    schedule 30.01.2011

  1. _MSC_VER — правильный макрос для обнаружения компилятора MSVC. Вы можете использовать __GNUC__ для GCC.

  2. Если вы собираетесь использовать popen в качестве идентификатора макроса, я предлагаю вам #include после этого из-за 3.

  3. Если вы #include сделаете это после stdio.h, это должно сработать, насколько я знаю, но лучше перестраховаться, чем потом сожалеть, не так ли? Назовите это portable_popen или как-то так.

  4. Во многих проектах (включая некоторые из моих) есть заголовок переносимости, но обычно лучше создать свой собственный. Я любитель делать что-то самостоятельно, если у вас есть время. Таким образом, вы знаете детали своего кода (его легче отлаживать, если что-то пойдет не так), и вы получаете код, адаптированный к вашим потребностям.

  5. Не то, что я знаю из. Я делаю такие вещи постоянно, без проблем.

person Oystein    schedule 30.01.2011

Вместо того, чтобы заканчиваться загроможденными файлами, содержащими блоки #ifdef..#else..#endif, я бы предпочел версию, использующую разные файлы для разных платформ:

  • поместите определения, зависящие от ОС, в один файл для каждой платформы и #define макрос my_popen
  • #include этот файл в вашем платформенно-независимом коде
  • никогда не вызывайте функции ОС напрямую, но созданные вами #define (т.е. my_popen)
  • в зависимости от вашей ОС используйте разные заголовки для компиляции (например, config/windows/mydefines.h в Windows и config/linux/mydefines.h в Linux, поэтому установите соответствующий путь включения и всегда #include "mydefines.h")

Это гораздо более чистый подход, чем наличие решения ОС в самом исходном коде.

Если методы, которые вы вызываете, ведут себя по-разному в Windows и Linux, решите, какой из них будет использоваться вами (т. е. либо всегда поведение Windows, либо всегда поведение Linux). а затем создайте методы-оболочки для достижения этой цели. Для этого вам также понадобятся не только два файла mydefines.h, но и файлы myfunctions.c, находящиеся в каталогах config/OSTYPE.

Делая это таким образом, вы также получаете преимущества, когда дело доходит до сравнения версий Linux и Windows: вы можете просто сравнить два файла, в то время как при сравнении блоков Linux и Windows одного и того же файла может быть трудный.

person eckes    schedule 30.01.2011