Using the C preprocessor
We already know that C is a language broadly used in almost every computer or computer-like gadget. We also know that C is a complex thing and thus every operative system has its own POSIX API in order to give some portability (Windows is special, I wo nt cover anything about Windows and C here).
So, as a student, I have assignments. I am also a Computer Science and
Engineering student, so some of those assignments are in low level languages (C
and C++). I use Mac and GNU/Linux day-to-day and will love using the POSIX API
in both operative systems without worring about library paths or some syscalls.
So, as far as I know, some library paths are different between Mac and
GNU/Linux, and thus we have to put those paths at the
#include macro. I am
going to write my findings about using the C preprocessor to solve this issue.
This is not a professional post but the findings of a student who likes C enough.
For this post I am using my MacBook Pro with the latest version of El Capitán and my Raspberry Pi B+ with the latest version of Raspbian at the date of writing this post.
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 8.0.0 (clang-800.0.42.1) Target: x86_64-apple-darwin15.6.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin
gcc (Raspbian 4.9.2-10) 4.9.2 Copyright (C) 2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
What is the Preprocessor?
The C preprocessor, often known as cpp, is a macro processor that is used automatically by the C compiler to transform your program before compilation. It is called a macro processor because it allows you to define macros, which are brief abbreviations for longer constructs.
The preprocessor does lexical substitutions, which is a hardcore copy and paste from macros to the source code!
When we want to define some constant values in C we can use the
#define macro is part of the preprocessor of C, so for example:
#define STRING "Hello, world"
You will get:
#define macro is widely used (e. g. look at the Linux’s source code).
It is cool, but there is no problem with this, it is easy to use and compatible with both operating systems.
So, for example, you can define macro calls! Let’s call it ’little functions’. So, for example, you need a comparator (because of… reasons). So, let’s define a macro for that:
#define equal(X, Y) ((X) == (Y) ? (X) : (Y))
It means: if X is equal to Y, returns X, else Y. It is an
if but in a macro!
And, of course, the output you get if true:
FALSE (2): 2 TRUE (1): 1
But, again, both operating systems have no problem with this, at all, it works cleanly.
As I said at the top of this post I wanted something more hardcore, like
distinguish between paths. In an assignments we had to upload for correction we
needed to use a lib. called
ucontext.h. So, why would I want to
use the preprocessor because of it? Well…
So… We need the preprocessor… Again! :).
Let’s get started seeing what are the macros we need. First of all, it is
neccesary to know the macros for both platforms, which are
__APPLE__ for Mac
__linux__ for GNU/Linux.
Of course, if you do that in Mac OS it prints
Mac OS if you compile and run in
a Mac and
GNU/Linux if you do it in Linux.
You can do it too for other macros (code:
ex4.c) which prints
100 if you
compile and run in a Mac and
200 if you do it in Linux.
Another example is for using different paths for a library:
#if __APPLE__ #include <sys/ucontext.h> #elif __linux__ #include <ucontext.h> #endif
That snippet is choosing between to paths for the same library. If there is some POSIX love between GNU/Linux and Mac, we should be able to use the same syscall of the same library. So, that means portability, and that is good! :D
As you can see C is really powerful and it was engineered in order to get portability from one operating system to another. POSIX allows it, and it is cool. I will edit this post to add things if I see more interesting stuff about the preprocessor that I could use and show you. This is bigger than you think, believe me!
You can get more info at GNU GCC’s Preprocessor wiki.
I am very thankful to @voiser who readed this post and pointed me some typos and grammatical errors that needed to be fixed :).