Commonly Used C Macros

I often find myself copying and pasting C macros from one program to another. Evidently I end up using these macros more often than I thought. So I thought I would share these useful macros with you. I will write about C macros later, C debugging macros and a guide to using C macros in your code. I find them quite useful, but how do macros affect the final product?

A macro (if not C99) is actually an inline expansion of your code. This means that the compiler will insert this code block directly into every spot you refer to the macro, rather than referencing the code block via a memory location. This can save pointer referencing and in some cases your code will be more efficient. You cannot, however, ensure this is the case the compiler may make decisions that it believes will be more efficient. None the less here is a list of some useful macros.

A Macro To Detect File Presence

Rather than attempting to open a file, you can use this macro:

#define exists(filename) (!access(filename, F_OK))

In your code you can then do something like:

if(exists("data.txt"))
  .. open file ...
else

Get The Size of An Array of Arbitrary Type

There are some instances where you don’t actually know the size of your array. This handy macro will tell you the size of your array, i.e. how many elements are in it:

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

This example utilizes the sizeof operator. You can use this macro as such:

int data[50];
fprintf(stdout, "Array size: %u\n",ARRAY_SIZE(data));

Min and Max

The always handy minimum and maximum macros will return the smaller or the larger of two items. These items can be of an arbitrary type, as long as they are the same type.

#define min(x,y) ({ \
	typeof(x) _x = (x);     \
	typeof(y) _y = (y);     \
	(void) (&_x == &_y);    \
	_x < _y ? _x : _y; })
 
 
#define max(x,y) ({ \
	typeof(x) _x = (x);     \
	typeof(y) _y = (y);     \
	(void) (&_x == &_y);    \
	_x > _y ? _x : _y; })

To use these macros, is much like any other:

int main()
{
  int a,b;
  a=5;
  b=12;
 
  fprintf(stdout, "%u\n", min(a,b));
  return 0;
}
$ ./min 
5

Voila, here are a few of the macros I find myself commonly using.

C Debugging Macros

Any experienced programmer can relate to sprinkling their code with printf statements to try and figure out a NULL pointer, or perhaps whether a function has been reached or not. This is the first step towards debugging code.   Further down the line can include using GDB or Valgrind to check code entry paths, modify variables during runtime or check memory usage or look for memory leaks from non-free malloc’d data upon program exit.  These tools are usually pulled out when the going gets tough!  As an initial pass during basic unit testing debug information is extremely handy.  What I usually attempt to do is create a header file (*.h) that can be included in any (*.c) files I happen to be working on.  This way, if I modify my macro it only requires a change in one place to complete.  For example:

#include <stdio.h>
#include <stdlib.h>
 
#ifdef DEBUG
#define DEBUGP(x, args ...) fprintf(stderr, " [%s(), %s:%u]\n" \
x, __FUNCTION__, __FILE__,__LINE__, ## args)
#else
#define DEBUGP(x, args ...)
#endif
 
void calculation() {
	DEBUGP("data: %u\n",5 * 5);
}
 
int main()
{
	DEBUGP("Program started.\n");
	calculation();
	return 0;
}

Now every time we want to output any debug information we can call DEBUGP(..data..);.  In doing so, we also get the file name, the function it was called in, and what line it occurred at.  This is extremely helpful for debugging purposes.  This macro utilizes the built-in C macros of __LINE____FUNCTION__, and __FILE__.   Another piece to note is, I have #ifdef DEBUG, this means that if this variable is defined then we can reference DEBUGP, if the DEBUG variable is not defined then we call our “#define DEBUGP(x, args …)“, which does not print out any debug data.  This means during compilation we can pass the -DDEBUG flag to the compiler, meaning we can turn on/off our debugging flag effortlessly.

So putting this all together, lets compile the program with the flag enabled.

erik@debian:/debug$ gcc -DDEBUG -o debug debug.c

Now that it is compiled lets run it.

erik@debian:/debug$./debug
[main(), debug.c:18] Program started.
[calculation(), debug.c:12] data: 25

So as we can see, with a little bit of organization and taking advantage of C macros we can make debugging a lot easier for ourselves!