2013-07-04 3 views
9

Меня спросили в интервью, как определить платформу только путем предоставления управляемого кода C?Определить платформу linux или windows с помощью кода C/C++

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

+1

как это? Http: // StackOverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor – chris

+2

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

+1

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

ответ

7

быстрый поиск Google показывает, что это

#if defined(_WIN64) 
    /* Microsoft Windows (64-bit). ------------------------------ */ 

#elif defined(_WIN32) 
    /* Microsoft Windows (32-bit). ------------------------------ */ 

#endif 

идентификации ОС макросы предопределены все/компиляторами C++ для включения # если/# ENDIF наборы, чтобы обернуть OS-зависимый код. Это часто необходимо в межплатформенном коде, который должен использовать низкоуровневые библиотечные функции для быстрого ввода-вывода, межпроцессного взаимодействия или потоков. Хотя различия между Windows и другими ОС остро стоят, даже различия между ОС в стиле UNIX могут потребовать конструкторы # if/# endif. В этой статье рассматриваются общие компиляторы и показано, как использовать предопределенные макросы для обнаружения общих операционных систем во время компиляции.

http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system

+0

+1 для ссылки. Дополнительные сведения о конкретных флагах ОС: https://users.pja.edu.pl/~jms/qnx/help/watcom/compiler-tools/cpwcc.html + https://github.com/emrainey/Concerto/ wiki/Predefined-Macros-for-Code – parasrish

2

Большинство распространенных способов сделать определение во время компиляции.

Если вы действительно настаиваете на принятии решения во время выполнения, вы можете попытаться использовать устройство (для одной возможности), которое существует на одном, но не на другом (например, попытка открыть файл с именем /dev/null должна работать на Linux но обычно не работает в Windows).

+1

Джерри, что если существует каталог C: \ dev и файл C: \ dev \ null? Например, эта команда отлично работает в этом случае: 'notepad/dev/null'. –

+0

@skwllsp: Да - вот почему я сказал «нормально». Если вам нужна более определенная возможность, я полагаю, вы могли бы создать каталог и сразу увидеть, можете ли вы открыть файл с именем «NUL» в этом каталоге (будет работать в Windows, а не в Linux). –

+0

@JerryCoffin Если единственными возможностями являются Windows и Linux на ПК, то самый простой (по крайней мере в 32-разрядном режиме) - это просто взять адрес локальной переменной в 'main'. Если это меньше, чем '0x80000000', вы находитесь под Windows. Если это больше, Linux. –

3

Это немного расплывчато. Бинарный файл не будет работать в обеих системах, если вы не запустите Wine (см. http://wiki.winehq.org/DeveloperFaq#detect-wine).

Во время компиляции вы можете проверить #define, специфичные для Windows или Linux, но, возможно, это компилятор и поддерживаемый стандарт, поэтому я не уверен, что вам разрешено делать это для целей (т. е., возможно, там есть ваша «нет специальных функций заголовков, используемых для проверки»).

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

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

Во время выполнения вы могли бы, например, stat("/dev", &buf), который должен работать только в Linux. Попытка popen (3) сказать, что uname - еще один правдоподобный подход: вы сможете прочитать «linux \ n», если вы находитесь на Linux, а в среде cygwin apparently reports NT, see here too.

+0

Ваше упоминание о вине это интересный вопрос. Если программа под управлением Wine сообщает Windows или Linux? (То же самое в обратном порядке для программы, скомпилированной с библиотеками CygWin под Windows.) –

+1

Реверс с Cygwin невозможен. Это исходный уровень совместимости (не двоичный), поэтому код должен быть скомпилирован специально для него. Он не запускает исполняемые файлы Linux в Windows (способ, которым Wine запускает двоичные файлы Windows в Linux). –

2

Помимо обычных MACRO вызовов:

#ifdef _WIN32 
    ... 

#if defined (_MSC_VER) 
    ... 

#ifdef __unix__ 
    ... 

Вы могли бы просто использовать функцию getenv() и тест на some variables set как SHELL или WINDIR.Интересные случаи, чтобы решить:

  • MinGW 32/64 под окнами 32/64
  • Cygwin 32/64 под окнами 32/64
  • вино под Linux 32/64

Конечно, Переменные среды Windows также могут быть установлены в Linux тоже - и наоборот.

1

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

How do I check OS with a preprocessor directive? Пожалуйста, перейдите по ссылке. Это может быть повторный вопрос.

5

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

Предположим, что у вас есть отдельные исполняемые файлы, есть действительно нет реального ответа. Для начала, что вы считаете «другой платформой »? Являются ли Linux на Sparc и Linux на ПК различными платформами ? Как насчет двух разных версий Linux? Что о запуске под CygWin? Независимо от того, как вы его определяете, , вам, вероятно, понадобится отдельный тест для каждой платформы. Но вопрос это глупо, потому что, кроме рассмотрения различных версий различных платформ, вам необходимо отчетливое исполняемый файл для каждой платформы, а это означает, что вы должны различать во время компиляции в любом случае

Только для записи : для начала я бы использовал boost :: filesystem, и попытался прочитать каталоги "c:\\" и "/usr". В теории у вас может быть каталог с именем "c:\\" в текущем каталоге под Unix или в каталоге с именем "/usr" в C: под Windows, но шансы определенно против него. В противном случае попробуйте различные файлы в "/proc/myPID". Каталог почти наверняка не существует под Windows, и , даже если это так, он не будет иметь динамическую структуру, которая имеет под различными Unix. И структура варьируется от одного Unix до , поэтому вы даже сможете отличить Solaris и Linux.

Если сравнить только Windows и Linux на ПК, то Конечно, проще всего скомпилировать в 32-битном режиме и принять адрес локальной локальной переменной . Если он больше 0x8000000, вы находитесь под Linux; если это меньше, Windows.

1

Если вы рассматриваете только платформу Linux или платформу Windows, этот код будет работать по мере необходимости на C и C++.

#include <stdio.h> 

#if defined(__linux__) // any linux distribution 
    #define PLATFORM "linux" 
#elif defined(_WIN32) // any windows system 
    #define PLATFORM "windows" 
#else 
    #define PLATFORM "Is not linux or windows" 
#endif 


int main(int argc, char *argv[]) { 
    puts(PLATFORM); 
    return 0; 
} 

Полный ответ на примере увидеть там https://stackoverflow.com/a/42040445/6003870

Смежные вопросы