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

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?

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.

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.

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.

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.

Related

How do I test if _Static_assert is defined?

_Static_assert is built-in to some C compilers such as gcc and clang, but it may not be included in all C compilers. I would like to use the _Static_assert functionality while keeping my code as cross-platform as possible. I figured the best way to do this was to test
#ifdef _Static_assert
_Static_assert(0, "Test");
#endif
but that doesn't seem to work out. It compiles, but it does not detect that _Static_assert is defined. Then I figured I could test if the compiler was GCC or not, but I read that having __GNUC__ defined doesn't necessarily prove that the compiler used is GCC. This also doesn't detect other compilers where _Static_assert is defined that I may not know about. So my question is, what is the best way to detect if the compiler supports _Static_assert in the preprocessor?
EDIT:
This is the solution I came up with that suits my purposes. Thanks to #KamilCuk below for the link that helped me out.
// Check that we can use built-in _Static_assert
#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L
#define WE_HAVE_STATIC_ASSERT 1
#endif
#if WE_HAVE_STATIC_ASSERT
_Static_assert(0, "Test");
#endif
This code works for me on both gcc and clang: https://godbolt.org/z/svaYjWj4j
FINAL EDIT (I think): This provides an answer to my original question about how to detect if _Static_assert is available. It also provides a fallback option that results in relatively helpful errors in most compilers I tested.
Here is the link to the test code: https://godbolt.org/z/TYEj7Tezd
// Check if we can use built-in _Static_assert
#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L
#define MY_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#else // We make our own
// MY_JOIN macro trick generates a unique token
#define MY_JOIN2(pre, post) MY_JOIN3(pre, post)
#define MY_JOIN3(pre, post) pre ## post
#if defined( __COUNTER__ ) // try to do it the smart way...
#define MY_JOIN(pre) MY_JOIN2(pre, __COUNTER__)
#define MY_STATIC_ASSERT(cond, msg) \
static const char *MY_JOIN(static_assert)[(cond) * 2 - 1] = { msg }
#else // we did our best...
//will break if static assert on same line in different file
#define MY_JOIN(pre) MY_JOIN2(pre, __LINE__)
#define MY_STATIC_ASSERT(cond, msg) \
static const char *MY_JOIN(static_assert)[(cond) * 2 - 1] = { msg }
#endif
#endif
/* - CHANGE CODE HERE TO TEST THE ASSERTIONS - */
enum {
A = 3,
B = 3,
C = B - A
};
/* - --------------------------------------- - */
// Test to see if the enum values match our assertions
MY_STATIC_ASSERT(B > A, "B must be greater than A");
MY_STATIC_ASSERT(C > 0, "C must be greater than zero");
Helpful information I used to make this came from these links:
http://jonjagger.blogspot.com/2017/07/compile-time-assertions-in-c.html
https://www.tutorialspoint.com/cprogramming/c_preprocessors.htm
https://stackoverflow.com/a/43990067/16292858
How do I test if _Static_assert is defined?
_Static_assert is part of C11. So check for C11.
#if __STDC_VERSION__ > 201112L
You could also #include <assert.h> and check for #ifdef static_assert.
My first google hit for static_assert.h github has a nice example how to handle different tools and compilers: https://github.com/wc-duck/dbgtools/blob/master/include/dbgtools/static_assert.h#L68 .
If you want to write a C11 compatibility layer and use static assertion in your code, for example use this answer and fallback to your own wrapper:
// static_assert.h
#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond) \
typedef struct { int static_assertion_failed : !!(cond); } \
CTASTR(static_assertion_failed_,__COUNTER__)
#include <assert.h>
#ifndef static_assert
#define static_assert(expr, str) STATIC_ASSERT(expr)
#endif
// somefile.c
#include <static_assert.h>
static_assert(something == something, "Uwu");

Compile only specific part of code when they are used

I have to make conditional compilation to skip some part of code when they are not being used. The project is a MCU project which consists of external modules like LEDs, LCD, Keypads etc.
I have a optimization.h file which is used to tell which modules are used at the time of compilation. It goes like this...
#ifndef OPTIMIZATION_H
#define OPTIMIZATION_H
// 1 - Compile code only for given modules
// 0 - Compile for all available modules
#define _OPTIMIZE_ 1
// Modules to compile
#define _LED_ 1
#define _SWITCH_ 1
// Modules not to compile
#define _LCD_ 0
#define _SSD_ 0
#endif
The code.c file goes like this...
#include "optimization.h"
void myFun()
{
// Compile when LED is used or all modules are asked to use
// i.e when _OPTIMIZE_ is 0 or _LED_ is 1
// Need to compile this code
#if !(_OPTIMIZE_) || (_LED_)
/* My code goes here */
#endif
// Need to compile this code
#if !(_OPTIMIZE_) || (_SWITCH_)
/* My code goes here */
#endif
// Need not to compile
#if !(_OPTIMIZE_) || (_LCD_)
/* My code goes here */
#endif
// Need not to compile
#if !(_OPTIMIZE_) || (_SSD_)
/* My code goes here */
#endif
}
If I wanted to use only LED and SWITCH only that part of code should be compiled. But all modules are compiled every time. What may be the problem...
The correct solution is to create a library with all the functions. Link your program against that library, and only the needed function will make it in the resulting binary.
For this to work you need to put each function into its own compilation unit. You could do this via separated source files, or with a single source file with preprocessor macro based selection and one compile command per option. I rather choose the first way.
I'm afraid that you simplified your problem too much so we are unable to assist. The following code runs fine on my machine:
#include <stdio.h>
/*** from Optimize.h ***/
// 1 - Compile code only for given modules
// 0 - Compile for all available modules
#define _OPTIMIZE_ 1
// Modules to compile
#define _LED_ 1
#define _SWITCH_ 1
// Modules not to compile
#define _LCD_ 0
#define _SSD_ 0
/*** from Code.c **/
int main()
{
// Need to compile this code
#if !(_OPTIMIZE_) || (_LED_)
printf ("Module LED included\n");
#endif
// Need to compile this code
#if !(_OPTIMIZE_) || (_SWITCH_)
printf ("Module SWITCH included\n");
#endif
// Need not to compile
#if !(_OPTIMIZE_) || (_LCD_)
This line is invalid C code.
printf ("Module LCD included\n");
#endif
}
Additionally I suggest to rename your preprocessor variables. Instead of #if !(_OPTIMIZE_) || (_LCD_), which are hard to read, you should write #if INCLUDE_ALL_MODULES || INCLUDE_LCD_MODULE. Consider also to use the construct #define INCLUDE_LCD_MODULE (INCLUDE_ALL_MODULES | 1).

C Pre-processor directives, Is this correct syntax? #Ifdef foo || bar

I have a pre-processor directive as such,
//#define SPEC_CONTROL // Is not defined, but can be if need be
#define SPEC_A_CONTROL // Is defined
#ifdef SPEC_CONTROL || SPEC_A_CONTROL
; // do something
#else
; // do something else
#endif
Is it correct syntax to use the || in the manner I did?
I can assure yout that at least
#if defined(SPEC_CONTROL) || defined(SPEC_A_CONTROL)
works on Windows and several UNIX platforms. Im not sure about
#ifdef SPEC_CONTROL || SPEC_A_CONTROL
You can use boolean logic in a C preprocessor directive by using the if defined directive.
See this post for more information:
C Preprocessor testing definedness of multiple macros

how to use #ifdef with an OR condition?

Sorry for asking very basic question. I would like to set OR condition in #ifdef directive.?
How to do that ?
I tried
#ifdef LINUX | ANDROID
...
..
#endif
It did not work? What is the proper way?
Like this
#if defined(LINUX) || defined(ANDROID)
OR condition in #ifdef
#if defined LINUX || defined ANDROID
// your code here
#endif /* LINUX || ANDROID */
or-
#if defined(LINUX) || defined(ANDROID)
// your code here
#endif /* LINUX || ANDROID */
Both above are the same, which one you use simply depends on your taste.
P.S.: #ifdef is simply the short form of #if defined, however, does not support complex condition.
Further-
AND: #if defined LINUX && defined ANDROID
XOR: #if defined LINUX ^ defined ANDROID

C Preprocessor testing definedness of multiple macros

I searched the site but did not find the answer I was looking for so here is a really quick question.
I am trying to do something like that :
#ifdef _WIN32 || _WIN64
#include <conio.h>
#endif
How can I do such a thing? I know that _WIN32 is defined for both 32 and 64 bit windows so I would be okay with either for windows detection. I am more interested in whether I can use logical operators like that with preprocessor directives, and if yes how, since the above does not work.
Compiling with gcc I get :
warning: extra tokens at end of #ifdef directive , and it basically just takes the first MACRO and ignores the rest.
Try:
#if defined(_WIN32) || defined(_WIN64)
// do stuff
#endif
The defined macro tests whether or not a name is defined and lets you apply logical operators to the result.
You must use #if and special operator defined
I think it should be possible this way:
#if defined block1 || defined block2 /*or any other boolean operator*/
/*Code*/
#endif
More information here
Use defined:
#if defined(A) || defined(B)
#include <whatever.h>
#endif

Resources