Properly handling platform specifics (unix/windows) in C? - c

This question is intentionally very generic and I'm not much of a C programmer although I dabble here and there. The following code is intentionally vague and probably won't compile, but I hope you get the point...
Handling platform specifics seems dynamically in a compiled language like C seems unnecessary and even scary:
int main(int argc, char *argv[]) {
if (windows)
dowindowsroutine();
else
dounixroutine();
return 0;
}
However, handling platform specifics through really very basic macros seems gross too as the function gets chopped up into small pieces which may not compile properly (read answer to C #define macro for debug printing for a similar problem).
int main(int argc, char *argv[]) {
#ifdef windows
dowindowsroutine();
#else
dounixroutine();
#endif
return 0;
}
So what's the "right" way to do this? Is it a case-by-case basis? Is there a good way to keep these gross macros out of functions entirely? I remember reading somewhere (probably in the kernel docs or something related) that macros (more importantly, complex macro logic) is meant for header files, not .c files. How do you handle this kind of stuff?
I'm sick of "spaghetti code" with ifdef's inside of functions... I spose there are some cases where it may be OK, but the majority of code I see abuse it.
Note: I've seen some perl XS code look like it wraps function prototypes to and things, but is that the only way? Isn't that somewhat gross in the community? Or is that OK? Coming from a mostly "scripted" background of perl, python, shell,... It's hard for me to tell.
Update: Let me be more clear, the problem I'm trying to avoid is that I don't want choppy code. I want to be able to ensure that if my code breaks at compile time in linux, it also breaks at compile time in windows. With the choppy code, its possible to break windows from compiling, but not linux and vice versa. Is this kind of thing possible? The closest thing to this so far is ifdef'ing the entire function, but the function names are the same, is there a better solution where there is one interface, but the OS specific parts have their OS name embedded into the name?

I think the right way to handle this is to split your code base into platform specific modules and have them assembled at build time (this of course requires some sort of platform abstraction layer.) That way your Unix code is not littered with Windows calls, and vise versa. Effectively you move your ifdef headache to the makefiles.

I've spent the better part of my career having to support multiple platforms concurrently. This is generally how I've approached the problem in the past: abstract out the platform-dependent bits and hide them behind a portable interface, create separate implementations of that interface for each platform you need to support, and use appropriate makefile magic to build what you need.
Example:
/**
* MyGenericModule.h
*/
typedef myAbstractType ...;
void genericFunction(MyAbstractType param);
...
This interface provides platform-neutral types and prototypes that the application code will reference.
/**
* Windows implementation
*/
#include "MyGenericModule.h"
#include "WindowsSpecificHeader.h"
...
void genericFunction(MyAbstractType param)
{
WindowsSpecificType lparam = convertToWindows(param);
/**
* Implement Windows-specific logic here
*/
}
This is the Windows version (WindowsModule.c).
/**
* Unix implementation
*/
#include "MyGenericModule.h"
#include "UnixSpecificHeader.h"
...
void genericFunction(MyAbstractType param)
{
UnixSpecificType lparam = convertToUnix(param);
/**
* Implement Unix-specific logic here
*/
}
And this is the Unix-specific version.
Now it's just a matter of setting up the right rules in your makefiles. Whether you build everything statically or build the platform-specific code into .dlls is driven less by portability and more by what makes sense for the application in question. Most of what I've done was linked statically.
Yes, it's a pain in the ass, but it scales much better than using the preprocessor. I've worked on "portable" code that was a nigh-unreadable rat's nest of #ifdefs . Never again.
The trick is getting the abstract types right, so that they contain everything the underlying implementation needs without overly burdening the programmer with implementation details. Yes, it's hard to do well, and I don't have any good "cookbook" examples to demonstrate.

In C++ or some other object-oriented language you could abstract the platform away and use a factory (etc) to instantiate the right kind of platform-specific implementation.
That said, if you need/want to #ifdef as outlined above I'd suggest something more like:
#if WINDOWS
void routine()
{
/* windows implementation here */
}
#else
void routine()
{
/* non-windows implementation here */
}
#endif
int main(int argc, char *argv[]) {
routine();
return 0;
}

Quite often the code fragments become large enough that it looks like this:
#if WINDOWS
void dowindowsroutine()
{
}
#else
void dounixroutine()
{
}
#endif
int main(int argc, char *argv[]) {
#if WINDOWS
dowindowsroutine();
#else
dounixroutine();
#endif
return 0;
}
Yes, here's an example of where you would indent preprocessor macros.
Sometimes it becomes large enough that we do it in the linker (linking against impwindows.o or impunix.o depending on makefile switch).

If you don't like ifdefs inside of functions... just write your code in such a way that the parts you would ifdef out, are taken into it's own function. And ifdef those functions. But just write your program naturally, don't re-write the entire program twice, one for windows and one for linux ;)

There is no absolute truth.
The way I would do it. I would abstract the routine away, and only call a single function that would check what platform you're using. I've included that as well because I like it so there.
#define PLATFORM_WINDOWS 0
#define PLATFORM_LINUX 1
#define PLATFORM_MACINTOSH 2
#define PLATFORM_WM6 3
#define PLATFORM_ANDROID 4
#define PLATFORM_SOMETHINGELSE 1000
#define COMPILER_VS6 1200
#define COMPILER_VSDOTNET 1300
#define COMPILER_VS2005 1400
#define COMPILER_VS2008 1500
#define COMPILER_GPP 100
#ifndef PLATFORM
/*
Detect which platform this is being run on.
Thanks go to Pixel Toaster for most of the flags.
*/
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
#define PLATFORM PLATFORM_WINDOWS
#define PLATFORM_NAME "Windows"
#elif defined(__APPLE__) || defined(__MACH__)
#define PLATFORM PLATFORM_MACINTOSH
#define PLATFORM_NAME "Macintosh"
#elif defined(linux) || defined(__linux) || defined(__linux__) || defined(__CYGWIN__)
#define PLATFORM PLATFORM_LINUX
#define PLATFORM_NAME "Linux"
#else
#define PLATFORM PLATFORM_SOMETHINGELSE
#define PLATFORM_NAME "Something Else"
#endif
/*
How many bits is this system?
*/
// Windows
#if (defined(_WIN64) || defined(WIN64))
#define PLATFORM_BITS 64
// Macintosh
#elif (defined(__LP64__) || defined(_LP64) || defined(__ppc64__))
#define PLATFORM_BITS 64
// Linux
#elif (defined(__x86_64__) || defined(__64BIT__) || (__WORDSIZE == 64))
#define PLATFORM_BITS 64
#else
#define PLATFORM_BITS 32
#endif
/*
Determine which compiler was used to compile this program.
*/
#ifdef _MSC_VER
#define COMPILER_VERSION _MSC_VER
#if (COMPILER_VERSION >= 1500)
#define COMPILER COMPILER_VS2008
#define COMPILER_NAME "Visual Studio 2008"
#elif (COMPILER_VERSION >= 1400)
#define COMPILER COMPILER_VS2005
#define COMPILER_NAME "Visual Studio 2005"
#elif (COMPILER_VERSION >= 1300)
#define COMPILER COMPILER_VSDOTNET
#define COMPILER_NAME "Visual Studio .NET"
#elif (COMPILER_VERSION >= 1200)
#define COMPILER COMPILER_VS6
#define COMPILER_NAME "Visual Studio 6"
#else
#error This version of Visual Studio is not supported.
#endif
#elif defined(__GNUC__)
// TODO: get actual compiler information for G++
#define COMPILER_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#define COMPILER_NAME "G++"
#define PLATFORM PLATFORM_LINUX
#endif
/*
Compiler specific options
*/
#if PLATFORM == PLATFORM_WINDOWS
// Support for Windows 98
#if COMPILER_VERSION >= COMPILER_VS6 && COMPILER_VERSION < COMPILER_VSDOTNET
#pragma comment(linker, "/OPT:NOWIN98")
#endif
#if COMPILER_VERSION >= COMPILER_VSDOTNET
#define FAST_CALL __declspec(noinline) __fastcall
#else
#define FAST_CALL __fastcall
#endif
#endif
#endif
#define MAIN int main(int argc, char *argv[])
void DoRoutine()
{
#if PLATFORM == PLATFORM_WINDOWS
// do stuff
#elif PLATFORM == PLATFORM_LINUX
// do other stuff
#endif
}
MAIN
{
DoRoutine();
}

You could create separate shared libraries for each platform (.so or .dll), then dynamically load the appropriate library at runtime. Each library would contain the platform-specific code. You would need a wrapper for the OS-specific load library calls, but that would probably be your only #ifdef'd function.

If you are really serious about handling platform dependent code (Everyone else, shield your eyes now!), you should look into imake or autoconf/automake, especially the latter.
Imake, originally used by the X window system, works something like knight666's answer; it uses a bunch of system-dependent configuration files to determine what exactly your system is and to allow you to handle the differences between systems. As far as I know, it never saw much actual usage, and judging by the Wikipedia page, even the X window system does not use it any more. Imake is a bit of a crawling horror.
Autoconf/automake (and libtool) are a bundle of shell scripts, Makefile templates, and m4 macros which generate the "configure" script known and loved by everyone who has built software on anything vaguely Unixish. The configure script runs a bunch of tests and then defines preprocessor macros and writes a Makefile, both of which allow your code to handle the system dependencies. If you are interested, a fairly decent book, GNU Autoconf, Automake, and Libtool, is available, although it looks to be hideously out of date. Autoconf and automake are a bit of a crawling horror.
Ideally, you would create a "platform abstraction layer" that hides the system-specific calls without duplicating any of your application logic. Typically, you will end up with #ifdef's or a code build system that only compiles the parts of the platform abstraction layer that match your specific platform.
Doing dynamic things like "if (windows) { doWindowsRoutine(); }" typically will not work, because doWindowsRoutine will not compile on a non-Windows machine.
In all, the whole area is more than a bit of a crawling horror.

Related

Preprocess C files, but only expand #ifdefs? [duplicate]

Original Question
What I'd like is not a standard C pre-processor, but a variation on it which would accept from somewhere - probably the command line via -DNAME1 and -UNAME2 options - a specification of which macros are defined, and would then eliminate dead code.
It may be easier to understand what I'm after with some examples:
#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif
If the command were run with '-DNAME1', the output would be:
#define ALBUQUERQUE "ambidextrous"
If the command were run with '-UNAME1', the output would be:
#define PHANTASMAGORIA "ghostly"
If the command were run with neither option, the output would be the same as the input.
This is a simple case - I'd be hoping that the code could handle more complex cases too.
To illustrate with a real-world but still simple example:
#ifdef USE_VOID
#ifdef PLATFORM1
#define VOID void
#else
#undef VOID
typedef void VOID;
#endif /* PLATFORM1 */
typedef void * VOIDPTR;
#else
typedef mint VOID;
typedef char * VOIDPTR;
#endif /* USE_VOID */
I'd like to run the command with -DUSE_VOID -UPLATFORM1 and get the output:
#undef VOID
typedef void VOID;
typedef void * VOIDPTR;
Another example:
#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
Ideally, I'd like to run with -UOLDUNIX and get the output:
#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
This may be pushing my luck!
Motivation: large, ancient code base with lots of conditional code. Many of the conditions no longer apply - the OLDUNIX platform, for example, is no longer made and no longer supported, so there is no need to have references to it in the code. Other conditions are always true. For example, features are added with conditional compilation so that a single version of the code can be used for both older versions of the software where the feature is not available and newer versions where it is available (more or less). Eventually, the old versions without the feature are no longer supported - everything uses the feature - so the condition on whether the feature is present or not should be removed, and the 'when feature is absent' code should be removed too. I'd like to have a tool to do the job automatically because it will be faster and more reliable than doing it manually (which is rather critical when the code base includes 21,500 source files).
(A really clever version of the tool might read #include'd files to determine whether the control macros - those specified by -D or -U on the command line - are defined in those files. I'm not sure whether that's truly helpful except as a backup diagnostic. Whatever else it does, though, the pseudo-pre-processor must not expand macros or include files verbatim. The output must be source similar to, but usually simpler than, the input code.)
Status Report (one year later)
After a year of use, I am very happy with 'sunifdef' recommended by the selected answer. It hasn't made a mistake yet, and I don't expect it to. The only quibble I have with it is stylistic. Given an input such as:
#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))
and run with '-UC' (C is never defined), the output is:
#if defined(A) && defined(B) || defined(D) && defined(E)
This is technically correct because '&&' binds tighter than '||', but it is an open invitation to confusion. I would much prefer it to include parentheses around the sets of '&&' conditions, as in the original:
#if (defined(A) && defined(B)) || (defined(D) && defined(E))
However, given the obscurity of some of the code I have to work with, for that to be the biggest nit-pick is a strong compliment; it is valuable tool to me.
The New Kid on the Block
Having checked the URL for inclusion in the information above, I see that (as predicted) there is an new program called Coan that is the successor to 'sunifdef'. It is available on SourceForge and has been since January 2010. I'll be checking it out...further reports later this year, or maybe next year, or sometime, or never.
I know absolutely nothing about C, but it sounds like you are looking for something like unifdef. Note that it hasn't been updated since 2000, but there is a successor called "Son of unifdef" (sunifdef).
Also you can try this tool http://coan2.sourceforge.net/
something like this will remove ifdef blocks:
coan source -UYOUR_FLAG --filter c,h --recurse YourSourceTree
I used unifdef years ago for just the sort of problem you describe, and it worked fine. Even if it hasn't been updated since 2000, the syntax of preprocessor ifdefs hasn't changed materially since then, so I expect it will still do what you want. I suppose there might be some compile problems, although the packages appear recent.
I've never used sunifdef, so I can't comment on it directly.
Around 2004 I wrote a tool that did exactly what you are looking for. I never got around to distributing the tool, but the code can be found here:
http://casey.dnsalias.org/exifdef-0.2.zip (that's a dsl link)
It's about 1.7k lines and implements enough of the C grammar to parse preprocessor statements, comments, and strings using bison and flex.
If you need something similar to a preprocessor, the flexible solution is Wave (from boost). It's a library designed to build C-preprocessor-like tools (including such things as C++03 and C++0x preprocessors). As it's a library, you can hook into its input and output code.

How do I check if I can use <sys/statvfs.h>?

I want to write a portable way to get the free disk space. On Windows, I use GetDiskFreeSpaceEx, and on Linux, the header <sys/statvfs.h> contains the function statvfs64() I can use.
My question is, on which systems I can assume that this header exists. Is there a macro I can check? Something like
#ifdef _MSC_VER
#include <windows.h>
#else
#ifdef STATVFS_IS_AVAILABLE
#include <sys/statvfs.h>
#endif
#endif
Generally, you would use autotools for stuff like that. autoconf creates a config.h header which defines a HAVE_STATVFS or so macro if you define a suitable configuration test.
However, due to the otherwise huge availability of <sys/statvfs.h>, you can also less portably simply test for _MSC_VER, as you just did.

C - Generate warning when loosely defined function is called

I'd like to generate a compiler warning for a specific situation. I'm building a sort of universal code that will be built based on several pre-compiler definitions. For instance I might have something like the following.
sdcard.h
#ifdef PART_BOARD1
#include "port/board1.h"
#elif PART_BOARD2
#include "port/board2.h"
#endif
extern void sdcardConfigure(void);
sdcard.c
#ifndef FLAG_SDCARD
#warning "No SD Card available for this board, or this board has not been defined"
#define sdcardConfigure(...) void(0)
#endif
port/board1.h (similar for port/board2)
#define FLAG_SDCARD
void sdcardConfigure(void);
port/board1.c
void sdcardConfigure(void) {
// sd card is configured here
}
Essentially what I'd like to do is modify the #define sdcardConfigure(...) statement in sdcard.c so that I'm only seeing the warning message if sdcardConfigure() is actually called. Making it act like:
void sdcardConfigure(void) {
#warning "sdcardConfigure() not available on this board"
}
The idea being that this gives me the flexibility to create a universal (I know many fear universal) program that adapts to the parts that it's using. I.E. if there is an SD Card use it, otherwise generate a warning saying "you're calling a function that doesn't exist for this part" and let the developer decide if the function is needed.
The answer to this will most-likely be compiler-dependent.
For gcc et al you can use __attribute__ ((deprecated)) (see gcc manual).
For Visual Studio you can use __declspec(deprecated).

How to avoid that C-header overwrites native C++ type

First I have to explain my ...
Situation
I have this microcontroller code (plain old C) which includes bool.h with the following content since stdbool.h is apparently not available, especially not with Visual Studio 2008, which is my current IDE for VC++ and C# (see below):
#ifndef CUSTOM_BOOL
#define CUSTOM_BOOL
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
#ifndef bool
#define bool unsigned char
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // #ifndef CUSTOM_BOOL
Now I need the functionality of that microcontroller code in a C# Project. That's why I created an intermediate Visual C++ Project containing managed classes that wrap the given microcontroller code.
Since this wrapper project (VC++) fiddles about the C code, it also has to #include "bool.h" (in an indirect way however, which means that another header is included, which itself includes bool.h - but I think that's an unimportant detail). Now here's my ...
Problem
Due to the fact that bool.h is included in the VC++ project and this project shall provide functions that return a "real" bool ("real" here means a type that is recognized as a bool by C# when using the VC++ project), unfortunately the bool in the VC++ code is also caught by the preprocessor and thus replaced by unsigned char. What happens now is, that C# complains in the end that a conversion from unsigned char to bool is not allowed. This is all okay and I understand why this happens. So here's my ...
Question
How can I solve this issue in a "clean" way. My current solution is, after including bool.h and right before the VC++ code starts, I undefine bool and friends again like this:
#ifdef bool
#undef bool
#endif
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
It works, but it breaks my proper-way-of-programming-heart. Is there a proper way to fix this? Or is the problem maybe happening before? Should I instead define something like BOOL instead of bool? According to my search on the interwebz, there is no general "standard" way to define bool (or BOOL?) in a C project (C99 is not supported) that everybody would agree upon.
So it sounds like the microcontroller project just made up a new data type and called it bool, which happens to conflict now that bool is a keyword (along with true and false)? My suggestions (in order of preference) would be:
Solution 1: Fix the microcontroller project.
Do a global search and replace on bool and replace it with something less contentious. Maybe C_Boolean, C_True, and C_False. Unlikely to cause any future conflicts and fairly simple to do using regular expressions.
Solution 2: Convert microcontroller project to C++.
This allows direct use of bool, true, and false (as keywords) and you can just eliminate the macros. This may prove difficult if the microcontroller code uses syntax that isn't c++ compatible.
Solution 3: Do what you've already done.
Create a wrapper include which cleans up after including your microcontroller code. I've got code that relies on redefining the extern keyword and this ends up being the only safe way for me. It's fragile though...you'll likely have to fix it in the future when something unrelated breaks the include structure.
Also, I'm not sure what the original author believes the extern "C" wrappers are doing but they have no effect on the macros being defined. Maybe you cut out some stuff that it would have an effect on, but the macros are unaffected by the linker name conventions.
You could convert the return value (the char) to a boolean value by using an operator. In this case, for instance, you could simply compare the return value this way:
bool b = 0 != functionthatreturnsaboolean();
Note that I'm not using 1 since the usualt definition of a boolean is 0 for false, anything else otherwise.
The other solution would be to simply use another type of return value. An integer should work well.
Edit: In light of the comment - you could also simply create an interface that calls those functions and returns a C# boolean value.
bool interfacefunction()
{
return function() != 0;
}
Thanks to Keith Thompson (comment under the question) and Speed8ump's answer, I got another idea:
bool.h:
#ifndef CUSTOM_BOOL
#define CUSTOM_BOOL
#ifndef __cplusplus
#ifndef bool
#define bool unsigned char
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#endif // #ifndef __cplusplus
#endif // #ifndef CUSTOM_BOOL
Works like a charm and I think it's a cleaner solution than the undefining stuff before. But still, feel free to comment or to provide more / better answers.

What are C macros useful for?

I have written a little bit of C, and I can read it well enough to get a general idea of what it is doing, but every time I have encountered a macro it has thrown me completely. I end up having to remember what the macro is and substitute it in my head as I read. The ones that I have encountered that were intuitive and easy to understand were always like little mini functions, so I always wondered why they weren't just functions.
I can understand the need to define different build types for debug or cross platform builds in the preprocessor but the ability to define arbitrary substitutions seems to be useful only to make an already difficult language even more difficult to understand.
Why was such a complex preprocessor introduced for C? And does anyone have an example of using it that will make me understand why it still seems to be used for purposes other than simple if #debug style conditional compilations?
Edit:
Having read a number of answers I still just don't get it. The most common answer is to inline code. If the inline keyword doesn't do it then either it has a good reason to not do it, or the implementation needs fixing. I don't understand why a whole different mechanism is needed that means "really inline this code" (aside form the code being written before inline was around). I also don't understand the idea that was mentioned that "if its too silly to be put in a function". Surely any piece of code that takes an input and produces an output is best put in a function. I think I may not be getting it because I am not used to the micro optimisations of writing C, but the preprocessor just feels like a complex solution to a few simple problems.
I end up having to remember what the macro is and substitute it in my head as I read.
That seems to reflect poorly on the naming of the macros. I would assume you wouldn't have to emulate the preprocessor if it were a log_function_entry() macro.
The ones that I have encountered that were intuitive and easy to understand were always like little mini functions, so I always wondered why they weren't just functions.
Usually they should be, unless they need to operate on generic parameters.
#define max(a,b) ((a)<(b)?(b):(a))
will work on any type with an < operator.
More that just functions, macros let you perform operations using the symbols in the source file. That means you can create a new variable name, or reference the source file and line number the macro is on.
In C99, macros also allow you to call variadic functions such as printf
#define log_message(guard,format,...) \
if (guard) printf("%s:%d: " format "\n", __FILE__, __LINE__,__VA_ARGS_);
log_message( foo == 7, "x %d", x)
In which the format works like printf. If the guard is true, it outputs the message along with the file and line number that printed the message. If it was a function call, it would not know the file and line you called it from, and using a vaprintf would be a bit more work.
This excerpt pretty much sums up my view on the matter, by comparing several ways that C macros are used, and how to implement them in D.
copied from DigitalMars.com
Back when C was invented, compiler
technology was primitive. Installing a
text macro preprocessor onto the front
end was a straightforward and easy way
to add many powerful features. The
increasing size & complexity of
programs have illustrated that these
features come with many inherent
problems. D doesn't have a
preprocessor; but D provides a more
scalable means to solve the same
problems.
Macros
Preprocessor macros add powerful features and flexibility to C. But they have a downside:
Macros have no concept of scope; they are valid from the point of definition to the end of the source. They cut a swath across .h files, nested code, etc. When #include'ing tens of thousands of lines of macro definitions, it becomes problematical to avoid inadvertent macro expansions.
Macros are unknown to the debugger. Trying to debug a program with symbolic data is undermined by the debugger only knowing about macro expansions, not the macros themselves.
Macros make it impossible to tokenize source code, as an earlier macro change can arbitrarily redo tokens.
The purely textual basis of macros leads to arbitrary and inconsistent usage, making code using macros error prone. (Some attempt to resolve this was introduced with templates in C++.)
Macros are still used to make up for deficits in the language's expressive capability, such as for "wrappers" around header files.
Here's an enumeration of the common uses for macros, and the corresponding feature in D:
Defining literal constants:
The C Preprocessor Way
#define VALUE 5
The D Way
const int VALUE = 5;
Creating a list of values or flags:
The C Preprocessor Way
int flags:
#define FLAG_X 0x1
#define FLAG_Y 0x2
#define FLAG_Z 0x4
...
flags |= FLAG_X;
The D Way
enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
FLAGS flags;
...
flags |= FLAGS.X;
Setting function calling conventions:
The C Preprocessor Way
#ifndef _CRTAPI1
#define _CRTAPI1 __cdecl
#endif
#ifndef _CRTAPI2
#define _CRTAPI2 __cdecl
#endif
int _CRTAPI2 func();
The D Way
Calling conventions can be specified in blocks, so there's no need to change it for every function:
extern (Windows)
{
int onefunc();
int anotherfunc();
}
Simple generic programming:
The C Preprocessor Way
Selecting which function to use based on text substitution:
#ifdef UNICODE
int getValueW(wchar_t *p);
#define getValue getValueW
#else
int getValueA(char *p);
#define getValue getValueA
#endif
The D Way
D enables declarations of symbols that are aliases of other symbols:
version (UNICODE)
{
int getValueW(wchar[] p);
alias getValueW getValue;
}
else
{
int getValueA(char[] p);
alias getValueA getValue;
}
There are more examples on the DigitalMars website.
They are a programming language (a simpler one) on top of C, so they are useful for doing metaprogramming in compile time... in other words, you can write macro code that generates C code in less lines and time that it will take writing it directly in C.
They are also very useful to write "function like" expressions that are "polymorphic" or "overloaded"; e.g. a max macro defined as:
#define max(a,b) ((a)>(b)?(a):(b))
is useful for any numeric type; and in C you could not write:
int max(int a, int b) {return a>b?a:b;}
float max(float a, float b) {return a>b?a:b;}
double max(double a, double b) {return a>b?a:b;}
...
even if you wanted, because you cannot overload functions.
And not to mention conditional compiling and file including (that are also part of the macro language)...
Macros allow someone to modify the program behavior during compilation time. Consider this:
C constants allow fixing program behavior at development time
C variables allow modifying program behavior at execution time
C macros allow modifying program behavior at compilation time
At compilation time means that unused code won't even go into the binary and that the build process can modify the values, as long as it's integrated with the macro preprocessor. Example: make ARCH=arm (assumes forwarding macro definition as cc -DARCH=arm)
Simple examples:
(from glibc limits.h, define the largest value of long)
#if __WORDSIZE == 64
#define LONG_MAX 9223372036854775807L
#else
#define LONG_MAX 2147483647L
#endif
Verifies (using the #define __WORDSIZE) at compile time if we're compiling for 32 or 64 bits. With a multilib toolchain, using parameters -m32 and -m64 may automatically change bit size.
(POSIX version request)
#define _POSIX_C_SOURCE 200809L
Requests during compilation time POSIX 2008 support. The standard library may support many (incompatible) standards but with this definition, it will provide the correct function prototypes (example: getline(), no gets(), etc.). If the library doesn't support the standard it may give an #error during compile time, instead of crashing during execution, for example.
(hardcoded path)
#ifndef LIBRARY_PATH
#define LIBRARY_PATH "/usr/lib"
#endif
Defines, during compilation time a hardcode directory. Could be changed with -DLIBRARY_PATH=/home/user/lib, for example. If that were a const char *, how would you configure it during compilation ?
(pthread.h, complex definitions at compile time)
# define PTHREAD_MUTEX_INITIALIZER \
{ { 0, 0, 0, 0, 0, 0, { 0, 0 } } }
Large pieces of text may that otherwise wouldn't be simplified may be declared (always at compile time). It's not possible to do this with functions or constants (at compile time).
To avoid really complicating things and to avoid suggesting poor coding styles, I'm wont give an example of code that compiles in different, incompatible, operating systems. Use your cross build system for that, but it should be clear that the preprocessor allows that without help from the build system, without breaking compilation because of absent interfaces.
Finally, think about the importance of conditional compilation on embedded systems, where processor speed and memory are limited and systems are very heterogeneous.
Now, if you ask, is it possible to replace all macro constant definitions and function calls with proper definitions ? The answer is yes, but it won't simply make the need for changing program behavior during compilation go away. The preprocessor would still be required.
Remember that macros (and the pre-processor) come from the earliest days of C. They used to be the ONLY way to do inline 'functions' (because, of course, inline is a very recent keyword), and they are still the only way to FORCE something to be inlined.
Also, macros are the only way you can do such tricks as inserting the file and line into string constants at compile time.
These days, many of the things that macros used to be the only way to do are better handled through newer mechanisms. But they still have their place, from time to time.
Apart from inlining for efficiency and conditional compilation, macros can be used to raise the abstraction level of low-level C code. C doesn't really insulate you from the nitty-gritty details of memory and resource management and exact layout of data, and supports very limited forms of information hiding and other mechanisms for managing large systems. With macros, you are no longer limited to using only the base constructs in the C language: you can define your own data structures and coding constructs (including classes and templates!) while still nominally writing C!
Preprocessor macros actually offer a Turing-complete language executed at compile time. One of the impressive (and slightly scary) examples of this is over on the C++ side: the Boost Preprocessor library uses the C99/C++98 preprocessor to build (relatively) safe programming constructs which are then expanded to whatever underlying declarations and code you input, whether C or C++.
In practice, I'd recommend regarding preprocessor programming as a last resort, when you don't have the latitude to use high level constructs in safer languages. But sometimes it's good to know what you can do if your back is against the wall and the weasels are closing in...!
From Computer Stupidities:
I've seen this code excerpt in a lot of freeware gaming programs for UNIX:
/*
* Bit values.
*/
#define BIT_0 1
#define BIT_1 2
#define BIT_2 4
#define BIT_3 8
#define BIT_4 16
#define BIT_5 32
#define BIT_6 64
#define BIT_7 128
#define BIT_8 256
#define BIT_9 512
#define BIT_10 1024
#define BIT_11 2048
#define BIT_12 4096
#define BIT_13 8192
#define BIT_14 16384
#define BIT_15 32768
#define BIT_16 65536
#define BIT_17 131072
#define BIT_18 262144
#define BIT_19 524288
#define BIT_20 1048576
#define BIT_21 2097152
#define BIT_22 4194304
#define BIT_23 8388608
#define BIT_24 16777216
#define BIT_25 33554432
#define BIT_26 67108864
#define BIT_27 134217728
#define BIT_28 268435456
#define BIT_29 536870912
#define BIT_30 1073741824
#define BIT_31 2147483648
A much easier way of achieving this is:
#define BIT_0 0x00000001
#define BIT_1 0x00000002
#define BIT_2 0x00000004
#define BIT_3 0x00000008
#define BIT_4 0x00000010
...
#define BIT_28 0x10000000
#define BIT_29 0x20000000
#define BIT_30 0x40000000
#define BIT_31 0x80000000
An easier way still is to let the compiler do the calculations:
#define BIT_0 (1)
#define BIT_1 (1 << 1)
#define BIT_2 (1 << 2)
#define BIT_3 (1 << 3)
#define BIT_4 (1 << 4)
...
#define BIT_28 (1 << 28)
#define BIT_29 (1 << 29)
#define BIT_30 (1 << 30)
#define BIT_31 (1 << 31)
But why go to all the trouble of defining 32 constants? The C language also has parameterized macros. All you really need is:
#define BIT(x) (1 << (x))
Anyway, I wonder if guy who wrote the original code used a calculator or just computed it all out on paper.
That's just one possible use of Macros.
I will add to whats already been said.
Because macros work on text substitutions they allow you do very useful things which wouldn't be possible to do using functions.
Here a few cases where macros can be really useful:
/* Get the number of elements in array 'A'. */
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))
This is a very popular and frequently used macro. This is very handy when you for example need to iterate through an array.
int main(void)
{
int a[] = {1, 2, 3, 4, 5};
int i;
for (i = 0; i < ARRAY_LENGTH(a); ++i) {
printf("a[%d] = %d\n", i, a[i]);
}
return 0;
}
Here it doesn't matter if another programmer adds five more elements to a in the decleration. The for-loop will always iterate through all elements.
The C library's functions to compare memory and strings are quite ugly to use.
You write:
char *str = "Hello, world!";
if (strcmp(str, "Hello, world!") == 0) {
/* ... */
}
or
char *str = "Hello, world!";
if (!strcmp(str, "Hello, world!")) {
/* ... */
}
To check if str points to "Hello, world". I personally think that both these solutions look quite ugly and confusing (especially !strcmp(...)).
Here are two neat macros some people (including I) use when they need to compare strings or memory using strcmp/memcmp:
/* Compare strings */
#define STRCMP(A, o, B) (strcmp((A), (B)) o 0)
/* Compare memory */
#define MEMCMP(A, o, B) (memcmp((A), (B)) o 0)
Now you can now write the code like this:
char *str = "Hello, world!";
if (STRCMP(str, ==, "Hello, world!")) {
/* ... */
}
Here is the intention alot clearer!
These are cases were macros are used for things functions cannot accomplish. Macros should not be used to replace functions but they have other good uses.
One of the case where macros really shine is when doing code-generation with them.
I used to work on an old C++ system that was using a plugin system with his own way to pass parameters to the plugin (Using a custom map-like structure). Some simple macros were used to be able to deal with this quirk and allowed us to use real C++ classes and functions with normal parameters in the plugins without too much problems. All the glue code being generated by macros.
Given the comments in your question, you may not fully appreciate is that calling a function can entail a fair amount of overhead. The parameters and key registers may have to be copied to the stack on the way in, and the stack unwound on the way out. This was particularly true of the older Intel chips. Macros let the programmer keep the abstraction of a function (almost), but avoided the costly overhead of a function call. The inline keyword is advisory, but the compiler may not always get it right. The glory and peril of 'C' is that you can usually bend the compiler to your will.
In your bread and butter, day-to-day application programming this kind of micro-optimization (avoiding function calls) is generally worse then useless, but if you are writing a time-critical function called by the kernel of an operating system, then it can make a huge difference.
Unlike regular functions, you can do control flow (if, while, for,...) in macros. Here's an example:
#include <stdio.h>
#define Loop(i,x) for(i=0; i<x; i++)
int main(int argc, char *argv[])
{
int i;
int x = 5;
Loop(i, x)
{
printf("%d", i); // Output: 01234
}
return 0;
}
It's good for inlining code and avoiding function call overhead. As well as using it if you want to change the behaviour later without editing lots of places. It's not useful for complex things, but for simple lines of code that you want to inline, it's not bad.
By leveraging C preprocessor's text manipulation one can construct the C equivalent of a polymorphic data structure. Using this technique we can construct a reliable toolbox of primitive data structures that can be used in any C program, since they take advantage of C syntax and not the specifics of any particular implementation.
Detailed explanation on how to use macros for managing data structure is given here - http://multi-core-dump.blogspot.com/2010/11/interesting-use-of-c-macros-polymorphic.html
Macros let you get rid of copy-pasted fragments, which you can't eliminate in any other way.
For instance (the real code, syntax of VS 2010 compiler):
for each (auto entry in entries)
{
sciter::value item;
item.set_item("DisplayName", entry.DisplayName);
item.set_item("IsFolder", entry.IsFolder);
item.set_item("IconPath", entry.IconPath);
item.set_item("FilePath", entry.FilePath);
item.set_item("LocalName", entry.LocalName);
items.append(item);
}
This is the place where you pass a field value under the same name into a script engine. Is this copy-pasted? Yes. DisplayName is used as a string for a script and as a field name for the compiler. Is that bad? Yes. If you refactor you code and rename LocalName to RelativeFolderName (as I did) and forget to do the same with the string (as I did), the script will work in a way you don't expect (in fact, in my example it depends on did you forget to rename the field in a separate script file, but if the script is used for serialization, it would be a 100% bug).
If you use a macro for this, there will be no room for the bug:
for each (auto entry in entries)
{
#define STR_VALUE(arg) #arg
#define SET_ITEM(field) item.set_item(STR_VALUE(field), entry.field)
sciter::value item;
SET_ITEM(DisplayName);
SET_ITEM(IsFolder);
SET_ITEM(IconPath);
SET_ITEM(FilePath);
SET_ITEM(LocalName);
#undef SET_ITEM
#undef STR_VALUE
items.append(item);
}
Unfortunately, this opens a door for other types of bugs. You can make a typo writing the macro and will never see a spoiled code, because the compiler doesn't show how it looks after all preprocessing. Someone else could use the same name (that's why I "release" macros ASAP with #undef). So, use it wisely. If you see another way of getting rid of copy-pasted code (such as functions), use that way. If you see that getting rid of copy-pasted code with macros isn't worth the result, keep the copy-pasted code.
One of the obvious reasons is that by using a macro, the code will be expanded at compile time, and you get a pseudo function-call without the call overhead.
Otherwise, you can also use it for symbolic constants, so that you don't have to edit the same value in several places to change one small thing.
Macros .. for when your &#(*$& compiler just refuses to inline something.
That should be a motivational poster, no?
In all seriousness, google preprocessor abuse (you may see a similar SO question as the #1 result). If I'm writing a macro that goes beyond the functionality of assert(), I usually try to see if my compiler would actually inline a similar function.
Others will argue against using #if for conditional compilation .. they would rather you:
if (RUNNING_ON_VALGRIND)
rather than
#if RUNNING_ON_VALGRIND
.. for debugging purposes, since you can see the if() but not #if in a debugger. Then we dive into #ifdef vs #if.
If its under 10 lines of code, try to inline it. If it can't be inlined, try to optimize it. If its too silly to be a function, make a macro.
While I'm not a big fan of macros and don't tend to write much C anymore, based on my current tasking, something like this (which could obviously have some side-effects) is convenient:
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
Now I haven't written anything like that in years, but 'functions' like that were all over code that I maintained earlier in my career. I guess the expansion could be considered convenient.
I didn't see anyone mentioning this so, regarding function like macros, eg:
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
Generally it's recommended to avoid using macros when not necessary, for many reasons, readability being the main concern. So:
When should you use these over a function?
Almost never, since there's a more readable alternative which is inline, see https://www.greenend.org.uk/rjk/tech/inline.html
or http://www.cplusplus.com/articles/2LywvCM9/ (the second link is a C++ page, but the point is applicable to c compilers as far as I know).
Now, the slight difference is that macros are handled by the pre-processor and inline is handled by the compiler, but there's no practical difference nowadays.
when is it appropriate to use these?
For small functions (two or three liners max). The goal is to gain some advantage during the run time of a program, as function like macros (and inline functions) are code replacements done during the pre-proccessing (or compilation in case of inline) and are not real functions living in memory, so there's no function call overhead (more details in the linked pages).

Resources