user1166981
user1166981

Reputation: 1746

C - How do you ignore certain code depending on the OS (so one source code to fit all)

I want to make the source of my program cross-platform, and so far so good. I have a couple of functions that only really differ in syntax, so I am checking some defines at the start to see if its windows or linux and setting a variable to 1 or 0 depending on which one it is. My thinking was that I could do an if statement check on that variable to skip the incorrect syntax usage. I have realised now that it won't compile because the compiler still 'sees' the offending code. Can you you

 #ifdef

to compartmentalize certain functions and call them within the code? Any suggestions?

Upvotes: 1

Views: 848

Answers (4)

Harry K.
Harry K.

Reputation: 640

Yes, in the simplest case and assuming for example a function called foo() you can do something like that...

/* Are we on a Windows platform ? */
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) || defined(__TOS_WIN__)
void foo( ... ) {
   /* windows implementation */
}

/* Are we on a Linux platform ? */
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
void foo( ... ) {
   /* linux implementation */
}

/* Are we on a Unix platform ? */
#elif defined(__unix__) || defined(__unix) || defined(unix)         \
|| defined(__CYGWIN__) || ( defined(__APPLE__) && defined(__MACH) )
void foo( ... ) {
   /* unix implementation */
}

/* Are we on Unsupported platform? */
#else
void foo( ... ) {
   /* generic implementation */
}
#endif

Another option is to have different header files for each OS that implement the different versions of the function(s), and then conditionally #include the appropriate one.

Assuming some header files called: myproj_win32.h, myproj_linux.h, myproj_unix.h, myproj_generic.h you could do something like this...

/* Are we on a Windows platform ? */
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) || defined(__TOS_WIN__)
#include "myproj_win32.h"

/* Are we on a Linux platform ? */
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
#include "myproj_linux.h"

/* Are we on a Unix platform ? */
#elif defined(__unix__) || defined(__unix) || defined(unix)         \
|| defined(__CYGWIN__) || ( defined(__APPLE__) && defined(__MACH) )
#include "myproj_unix.h"
}

/* Are we on Unsupported platform? */
#else
#include "myproj_generic.h"
#endif

Only the correct version of the implementation will be compiled. There are more options, but those should be fine to get you started.

EDIT

Here is a useful link with pre-defined macros for common C/C++ compilers.

Upvotes: 1

jim mcnamara
jim mcnamara

Reputation: 16389

cpp -d M < /dev/null > somefile will show the default feature test macro settings (#define values) you can expect from a compiler - for the macros (#ifdef) stuff you want to test for. You have to run this on every system, plus some compilers add macros by default e.g. gcc.

#ifdef _SUN_OS 
// put all Sun OS code here

#endif

You will have to find the macros to identify all of your platforms.

Upvotes: 1

peppe
peppe

Reputation: 22796

Of course you can, that's pretty much the standard way of doing that, at least for small parts of code. For bigger chunks, you might want to use the buildsystem instead, and have platform-specific code in separated files (foo_win.c, foo_unix.c); then, depending on the OS, you compile and link in the application only the right ones.

There are a lot of preprocessor defines that will tell you OS, compiler, architecture and other things; take a look at how Qt detects the OS or the compiler.

Upvotes: 1

Simon
Simon

Reputation: 32933

You have to enclose the entire non cross-platform section between #ifdefs.

For instance:

int gettimeofday(struct timeval *tp, void *tzp)
{
#ifdef WIN32

    struct _timeb timebuffer;

    _ftime(&timebuffer);
    tp->tv_sec = timebuffer.time;
    tp->tv_usec = timebuffer.millitm * 1000;

    return 0;

#else

    tp->tv_sec = time(NULL);
    tp->tv_usec = 0;

    return 0;

#endif
}

Like this the compiler won't see the offending code since it is removed at the preprocessing step.

Upvotes: 4

Related Questions