C Macros – Using Macros to Protect Global Variable Assignments

api-designcglobalsheadersmacros

Because there is no language feature in C to protect assignment to global variables would you recommend doing something like this?

Take this example:

We have a module with the header file called module.h and
implementation file module.c. The module contains a global variable
called global_variable. global_variable will be updated by other functions
in the implementation but we do not want users of module to be able
to assign to it.

module.h:

#ifndef MODULE_H_
#define MODULE_H_

extern int global_variable;
#define global_variable (int)global_variable
/* Because the macro expansion is not an "lvalue" it cannot be assigned to. */

/* ... */

#endif

In the implementation you just #undef the macro to get full read/write access to it.

module.c:

#include "module.h"
#undef global_variable /* Make `global_variable` mutable again. */

int global_variable = 17;

/* ... */

This method obviously has the disadvantage that you cannot create a local variable with the identifier global_variable without #undefing the macro.

#include "module.h"

int f(void)
{
    int global_variable; /* This doesn't work. */
    /* ... */
}

But if you manage to come up with a naming convention that separates the identifiers this will not be a problem. Something like prefixing global variables with glbl_ or GLBL_. GLBL_ seems like a good choice since that also gives you a hint that it can be defined as a macro.

Another technique I have figured out is this:

module.h:

#ifndef MODULE_H_
#define MODULE_H_

#ifdef MODULE_IMPL_
extern int global_variable; /* Writable for the implementation. */
#else
extern const int global_variable; /* `readonly` for everyone else. */
#endif

/* ... */

#endif

module.c:

#define MODULE_IMPL_ /* I am the implementation. I want global_variable to be mutable. */
#include "module.h"

int global_variable = 17;

/* ... */

I know that the simplest and most flexible approach is to create get functions to retrieve the value of the variable at the cost of a function call. But that does not stop me from finding other hacks to solve the problem.

Are these evil things to do? I am not going to lie, I like to play with macros. But I want to know if this is something that can be applied to a serious project. 🙂

Best Answer

Using macros to create code that's syntactically identical to C but semantically different is almost always evil, especially in an unsafe language like C where the fact that something compiles in no way guarantees it actually has defined behavior at run time. If you must use a macro for something, you generally want to make it clear that a macro is being used.

For this particular case you can achieve your goal better by not exposing the variable at all (i.e. make it static) and providing a function to read its value. You get the same end result (the value is read-only from outside the implementation file) but avoid using macros and their associated pitfalls altogether. Even better, don't use a global variable at all if you can; pass the value to the functions that need it.

Related Topic