DEV Community

Kshitij Srivastava
Kshitij Srivastava

Posted on • Edited on

Saving Magic for Macros

We often find ourselves in the middle of writing a function that we cannot bring ourselves to simplify further. The ones which end up relying on some kind of inexplicable "magic" that cannot be abstracted away.

Instead of writing these as functions, consider using macros instead. Let me give you a taste of what they are capable of.

Macros are defined using the #define directive and are effectively a copy-paste replacement where they are used with appropriate parameter substitutions.

#include <stdio.h>

#define PRINT_MESSAGE(message) printf("%s\n", (message))

int main(void) {
    PRINT_MESSAGE("Hello, world!");
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Macros are incredibly powerful since they accept any token as a parameter. So, you could potentially also do this.

#define PERFORM_OPERATION(number_1, number_2, operator) \
    ((number_1) operator (number_2))

int main(void) {
    int a = PERFORM_OPERATION(1, 2, +);  // 3
    int b = PERFORM_OPERATION(1, 2, -);  // -1
    int c = PERFORM_OPERATION(5, 2, *);  // 10
    int c = PERFORM_OPERATION(4, 2, /);  // 2

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

But, my personal favourite use of macros is to create generic versions of certain often used procedures. Here's one that is used to swap two values of any given data type.

#include <stdbool.h>
#include <stdlib.h>

#define SWAP(value_1, value_2, type)\
    do\
    {\
        type* temp = malloc(sizeof(type));\
        *temp = value_1;\
        value_1 = value_2;\
        value_2 = *temp;\
        free(temp);\
    }\
    while (false)
Enter fullscreen mode Exit fullscreen mode

Let me try to explain the weirdness. Since we're creating a variable and since macros are effectively a copy-paste substitution, we have to limit the variable's scope. So, we can place it in a separate block like this do-while block that only executes once.

This function would have been a pain to write normally since there is no direct way to pass the data-type to a function in C. In situations like this, it is often much easier to write a simple macro than to create multiple long and similar functions.

Top comments (5)

Collapse
 
pauljlucas profile image
Paul J. Lucas • Edited

There is no reason to use malloc in your SWAP example:

type temp = value_1;
value_1 = value_2;
value_2 = temp;
Enter fullscreen mode Exit fullscreen mode

Using the do...while loop is not only for scope, but also to ensure it's treated as a single statement:

if ( some_condition )
    SWAP( a, b );
Enter fullscreen mode Exit fullscreen mode

That code would break if it were not inside a do...while.

Anyway, you barely scratched the surface regarding macros. For example, you never explain why you use \ at the end of lines. See here.

Collapse
 
k-srivastava profile image
Kshitij Srivastava

You are correct about the nature of do...while, my bad for forgetting to mention its other purpose. This post is just meant as a taste of what macros can do, not necessarily a guide or even best practice.

Collapse
 
pauljlucas profile image
Paul J. Lucas

The problem with "taste" articles is: unless you explicitly say the article is only a taste, the reader has no idea there's more to learn.

Thread Thread
 
k-srivastava profile image
Kshitij Srivastava

Fair enough. Updated the body to make it more evident. Although, it seems quite clear from the onset that this isn't a deep-dive.

Thread Thread
 
pauljlucas profile image
Paul J. Lucas

Clear to you; but not necessarily to someone who doesn't know C.