10

我在一次采访中被问到如何仅通过提供可运行的 C 代码来识别平台?

代码必须在两个平台上都可以运行(即没有用于检查的特殊头文件功能)?

4

7 回答 7

7

快速的谷歌搜索显示了这一点

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

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

#endif

操作系统标识宏由所有 C/C++ 编译器预定义,以启用 #if/#endif 集来包装操作系统特定的代码。这在必须使用低级库函数进行快速磁盘 I/O、进程间通信或线程的跨平台代码中通常是必需的。虽然 Windows 和其他操作系统之间的差异很明显,但即使是 UNIX 风格的操作系统之间的差异也可能需要 #if/#endif 构造。本文调查了常见的编译器,并展示了如何使用预定义的宏在编译时检测常见的操作系统。

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

于 2013-07-04T07:28:03.663 回答
6

这个问题很奇怪。您不能提供可以在多个平台上运行的可执行文件。所以显而易见的答案是:在一个平台上编译它:如果它运行,那就是你所在的平台;如果不是,您在其他平台上。

假设您确实有单独的可执行文件,那么实际上没有真正的答案。首先,您认为“不同的平台”是什么?Sparc 上的 Linux 和 PC 上的 Linux 是不同的平台吗?那么两个不同版本的 Linux 呢?在 CygWin 下运行呢?但是,无论您如何定义它,您都可能需要对每个平台进行单独的测试。但是这个问题很愚蠢,因为除了考虑不同平台的不同版本之外,您需要为每个平台提供不同的可执行文件,这意味着无论如何您必须在编译时进行区分

仅作记录:对于初学者,我会使用 boost::filesystem,并尝试读取目录"c:\\""/usr". 理论上,您可以"c:\\"在 Unix 下拥有一个以当前目录命名的目录,或者"/usr"在 Windows 下拥有一个以 C: 命名的目录,但绝对不可能。否则,请尝试. 该目录在 Windows 下几乎肯定不存在,即使存在,也不会有它在各种 Unix 下的动态结构。并且结构从一个Unix到另一个不同,所以你甚至应该能够区分Solaris和Linux。"/proc/myPID"

如果只是在PC上比较Windows和Linux,当然最简单的就是32位编译,取一个局部变量的地址。如果大于0x8000000,说明你在Linux下;如果它更少,Windows。

于 2013-07-04T08:18:36.607 回答
3

这有点模糊。除非您在 Wine 下运行,否则二进制文件不会在两个系统中运行(请参阅http://wiki.winehq.org/DeveloperFaq#detect-wine)。

在编译时,您可以检查特定于 Windows 或 Linux 的#defines,但可以说这是特定于编译器和支持的标准,所以我不确定您是否“允许”出于面试问题的目的这样做(即,可以说它与您的“没有用于检查的特殊头文件功能”限制有关)。

一般来说,我认为优先于编译时检查没有任何意义,而且它可能在 Wine 下不起作用,但您可以使用它dlsym()来检查自己是否存在已知仅存在于一个操作系统上的符号,或查看您自己的可执行映像以了解它是什么。

实际上,您也很可能可以检查您的环境变量并据此做出相当好的判断,尽管有人可能会故意欺骗您的程序进行不正确的评估,或者您的判断方法可能会在未来版本的操作系统中中断, 在不同的外壳下等..

在运行时,您可以例如stat("/dev", &buf),它应该只在 Linux 上工作。尝试popen(3) 说uname是另一种可行的方法:如果您在 Linux 上,您将能够阅读“linux\n”,而类似 cygwin 的环境显然会报告NT请参见此处

于 2013-07-04T07:31:03.677 回答
2

除了通常的 MACRO 调用:

#ifdef _WIN32
  ...

#if defined (_MSC_VER)
  ...

#ifdef __unix__
  ...

您可以简单地使用该getenv()函数并测试一些变量集,如SHELLor WINDIR。有趣的案例要决定:

  • windows 32/64下的mingw 32/64
  • windows 32/64下的cygwin 32/64
  • linux下的wine 32/64

当然,“Windows”环境变量也可以在 Linux 中设置——反之亦然。

于 2013-07-04T07:31:14.137 回答
2

大多数常用方法在编译时进行确定。

如果您真的坚持在运行时做出决定,您可以尝试使用一个设备(出于一种可能性)存在于一个设备上但不存在于另一个设备上(例如,尝试打开一个名为的文件/dev/null应该可以在 Linux 上工作,但在 Windows 上通常会失败)。

于 2013-07-04T07:28:52.953 回答
2

如果您只考虑 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

于 2017-02-04T12:42:30.707 回答
1

每个平台都定义了自己的预处理器指令。您必须在其中编写代码。

如何使用预处理器指令检查操作系统? 请按照上面的链接。可能是重复的问题。

于 2013-07-04T08:04:40.790 回答