Самый стандартный способ выбрать имя функции в зависимости от платформы? - PullRequest
5 голосов
/ 30 января 2011

В настоящее время я использую функцию 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. Что-нибудь еще, о чем я должен знать?

Ответы [ 4 ]

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

То, как вы это делаете, прекрасно (с #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
1 голос
/ 30 января 2011
  1. _MSC_VER - правильный макрос для обнаружения компилятора MSVC. Вы можете использовать __GNUC__ для GCC.

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

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

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

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

0 голосов
/ 30 января 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: вы можете просто различать два файла, выполняя diff для блоков linux и windows одного и того же файла может быть трудно.

...