11

I was asked in an interview to how would you identify the platform only by providing runnable C code?

The code must be runnable in both platform(i.e no special header files function used to check)?

Ayush Pant
  • 119
  • 1
  • 8
  • 1
    Like this? http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor – chris Jul 04 '13 at 07:23
  • 2
    those questions talk about macros, but I think the OP is really asking if how you'd do it with code which you could compile on multiple platforms. I'd suggest probing the file system for the presence of files which revealed the operating system. – Paul Dixon Jul 04 '13 at 07:28
  • 1
    Conceptually, it would probably make more sense to solve this on the build-environment level instead of the language level. I.e. have the build environment define a preprocessor flag that allows the code to determine the platform. Otherwise you introduce knowledge about the compiler into the source, which restricts portability and is not so nice in general. – ComicSansMS Jul 04 '13 at 08:00
  • 2
    I guess the question is not about compiler directives because they are not runnable c code right ? it is more like what code do I use to detect the platform. Weird because you have to compile C code for the specific platform anyway. Guess the question is a bit ambiguous for me. – Philip Stuyck Jul 04 '13 at 08:10
  • 2
    How does this get marked as a duplicate. It's a completely different question. (It may be a nonsense question, or a question which doesn't have an answer, but it's certainly not the same question as the one linked to as a duplicate.) – James Kanze Jul 04 '13 at 08:25

7 Answers7

7

a quick google search shows this

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

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

#endif

OS identification macros are predefined by all C/C++ compilers to enable #if/#endif sets to wrap OS-specific code. This is often necessary in cross-platform code that must use low-level library functions for fast disk I/O, inter-process communications, or threads. While differences between Windows and other OSes are acute, even differences among UNIX-style OSes can require #if/#endif constructs. This article surveys common compilers and shows how to use predefined macros to detect common OSes at compile time.

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

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • +1 for the link. More of the OS specific flags info at : https://users.pja.edu.pl/~jms/qnx/help/watcom/compiler-tools/cpwcc.html + https://github.com/emrainey/Concerto/wiki/Predefined-Macros-for-Code – parasrish Oct 11 '17 at 13:04
6

The question is wierd. You can't provide an executable which can run on multiple platforms. So the obvious answer is: compile it on one platform: if it runs, that's the platform you're on; if it doesn't you're on some other platform.

Supposing that you do have separate executables, there's really no real answer. For starters, what do you consider "a different platform"? Are Linux on a Sparc and Linux on a PC different platforms? What about two different versions of Linux? What about running under CygWin? Regardless of how you define it, though, you'll probably need a separate test for each platform. But the question is silly, because, except for considering different versions different platforms, you'll need a distinct executable for each platform, which means that you have to distinguish at compile time anyway

Just for the record: for starters, I'd use boost::filesystem, and try to read directories "c:\\" and "/usr". In theory, you could have a directory named "c:\\" in the current directory under Unix, or a directory named "/usr" in C: under Windows, but the odds are definitely against it. Otherwise, try various files in "/proc/myPID". The directory will almost certainly not exist under Windows, and even if it does, it won't have the dynamic structure it has under various Unix. And the structure varies from one Unix to the next, so you should even be able to distinguish between Solaris and Linux.

If the comparison is just between Windows and Linux on a PC, of course, the simplest is to compile in 32 bit mode, and take the address of a local variable. If it's greater than 0x8000000, you're under Linux; if it's less, Windows.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • if we have to compile only in 64 bit mode on both platforms, is there a way i can differentiate between the two platforms with addresses? – Manjunath Oct 11 '18 at 18:42
3

That's a bit vague. A binary won't run in both systems unless you run under Wine (then see http://wiki.winehq.org/DeveloperFaq#detect-wine ).

At compile time you can check for #defines specific to Windows or Linux, but arguably that's compiler- and supported-Standards-specific, so I'm not sure if you're "allowed" to do that for the purposes of the interview question (i.e. it's arguably in there with your "no special header files function used to check" restriction).

In general I don't think it makes any sense to do in preference to compile-time checks, and it might not work under Wine, but you could use dlsym() to check yourself for symbols known to be present on only one of the Operating Systems, or look at your own executable image to see what it is.

Practically, it's also very likely you can inspect your environment variables and make a pretty good determination based on that, though someone might be able to deliberately fool your program into an incorrect assessment, or your determination method might break in future versions of the Operating Systems, under different shells etc..

At run-time, you could e.g. stat("/dev", &buf), which should only work on Linux. Trying to popen(3) say uname is another plausible approach: you'll be able to read "linux\n" iff you're on Linux, while a cygwin-like environment apparently reports NT, see here too.

Community
  • 1
  • 1
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • Your mention of Wine is an interesting question. Should a program running under Wine report Windows or Linux? (Same thing in reverse for a program compiled with the CygWin libraries under Windows.) – James Kanze Jul 04 '13 at 08:23
  • 1
    The reverse with Cygwin is not possible. It's a source compatibility layer (not binary) so code must be compiled specifically for it. It does not run Linux binaries on Windows (the way Wine runs Windows binaries on Linux). – nobody May 01 '15 at 11:54
2

Most of the common methods make the determination at compile time.

If you really insist on making the determination at run time, you could attempt to use a device (for one possibility) that exists on one but not the other (e.g., attempting to open a file named /dev/null should work on Linux but normally fail on Windows).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    Jerry, what if exists a directory C:\dev and file C:\dev\null? For example this command works fine in this case: `notepad /dev/null`. –  Jul 04 '13 at 07:35
  • @skwllsp: Yes -- that's why I said "normally". If you need a more certain possibility, I suppose you could create a directory, and immediately see if you can open a file named "NUL" in that directory (will work on Windows, not on Linux). – Jerry Coffin Jul 04 '13 at 07:43
  • @JerryCoffin If the only possibilities are Windows and Linux on a PC, then the simplest (at least in 32 bit mode) is just to take the address of a local variable in `main`. If it's less than `0x80000000`, you're under Windows. If it's greater, Linux. – James Kanze Jul 04 '13 at 08:21
  • @JamesKanze: That sounds to me like an excellent answer. – Jerry Coffin Jul 04 '13 at 15:55
  • @JerryCoffin It sounded to me like a very big if. Using this rule, Solaris on a Sparc will look like Linux; HP-UX will show up like Windows. And I have no idea off hand what Apple will show up as. (Probably Linux, since it is Unix using g++ and running on an Intel architecture. But you never know.) – James Kanze Jul 04 '13 at 16:16
  • @JamesKanze: Well, frankly, the whole idea sounds iffy to me. While I did try to answer, I don't see any rational reason you'd try to sort this out at run-time, when there are plenty of ways of handling it at compile time. With something like Java, run-time detection can make sense, but until/unless VM-based implementations of C and/or C++ become common, the whole idea seems less than sensible. – Jerry Coffin Jul 04 '13 at 16:24
  • @JerryCoffin I totally agree. You can't run the same binary on two different systems, so you have to compile twice anyway. At which point, it's a lot easier to make the distinction at compile times. (There's also the question of what you do with the distinction. Something like `if ( windows ) LoadLibrary(...); else dlopen(...);` isn't going to link anywhere.) – James Kanze Jul 04 '13 at 16:36
2

Aside from the usual MACRO invocations:

#ifdef _WIN32
  ...

#if defined (_MSC_VER)
  ...

#ifdef __unix__
  ...

You could simply use the getenv() function and test for some variables set like SHELL or WINDIR. Interesting cases to decide:

  • mingw 32/64 under windows 32/64
  • cygwin 32/64 under windows 32/64
  • wine under linux 32/64

Of course, "Windows" environment variables can be set in Linux too - and vice-versa.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
rubber boots
  • 14,924
  • 5
  • 33
  • 44
2

If you considering only the Linux platform or the Windows platform, this code will be work as needed to you on C and 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;
}

A full answer with an example see there https://stackoverflow.com/a/42040445/6003870

Community
  • 1
  • 1
PADYMKO
  • 4,217
  • 2
  • 36
  • 41
1

Every platform has own pre processor directive defined. You have to write the codes within it it.

How do I check OS with a preprocessor directive? Please follow above link. It may be repeated question.

Community
  • 1
  • 1
pcbabu
  • 2,219
  • 4
  • 22
  • 32