User-Defined Functions and Macros

When you desire to do something specific in your program, or have a chunk of code that’s duplicated elsewhere, you craft a function. That’s the traditional, problem-solving approach, and the C language is full of functions. Yet sometimes, programmers build macros instead of functions.

In C programming, macro refers to a function created by using the #define preprocessor directive. In most of my sample code on this blog, #define creates a constant. The compiler expands the constant into whatever value is set, which is a handy way to control some limits within the code.

The #define directive can also be used to replace symbols, which is bizarre but some programmers do it. And it’s used to build macros, which are like functions but typically shortcuts for more complex code elsewhere.

For example, the old warhorse the max() function is presented in beginning programming lessons as a function that returns the larger of two values. This code can be written as a function, which might look like this:

int max(int a, int b)
{
    if(a > b)
        return(a);
    return(b);
}

The sample above is just one way to solve the puzzle. You might also see a max macro, defined as follows:

#define max( a, b) a > b ? a : b

The macro defines max like a function, but it’s not a function. Instead, it’s a definition that the compiler populates throughout the code wherever the word max appears. Specifically, max would look like this:

max(100,2);

The compiler would substitute the above statement with the following:

100 > 2 ? 100 : 2;

That’s ternary expression is evaluated as a value C language statement. The effect is the same as desired for a max() function, but the code is defined as a macro instead of written as a function.

C programmers tend to adore the #define macros. In fact, a lot of the functions you use might be set as macros within the various header files. The man page hints at whether the “function” is actually a macro, though the only way to know for certain is to examine the header file. Even then not every compiler may use a macro; some may implement a true function instead.

I tend to prefer functions over macros because macros are difficult to document and not as easy to read. Still, it’s kind of fun to craft a macro and use it in your code. As you can see from the samples above, it makes for a solution to interesting challenges. In the following code, the charout() function is actually a macro, defined at Line 3:

#include <stdio.h>

#define charout( c ) fputc(c,stdout)

int main()
{
    char text[] = "Hello, there!\n";
    int x = 0;

    while(text[x])
    {
        charout(text[x]);
        x++;
    }

    return(0);
}

The charout() “function” at Line 12 is expanded by the compiler to equal:

fputc(text[x],stdout);

Of course, you could have written that line just as easily, but perhaps the programmer is more familiar with a charout() function from another language? Who knows! Still, you can use macros to simplify the way some code is presented. I’ll cover another example in next week’s Lesson.

Leave a Reply