Rose Kunkel
Rose Kunkel

Reputation: 3268

Forcing preprocessor error with macro

Is there a way that I can force a preprocessor macro in C++ to emit an error? What I would like to do is define a macro UNKNOWN. I'm writing some code for a robot, and I don't yet know where all of the electronics are being plugged in. I'd like to be able to define the ports in some header file, like

const int MOTOR_PORT = 1;
const int FAN_PORT = 2;
//etc.

However, when I reach a port that I don't yet know, I want to be able to write something like

const int LED_PORT = UNKNOWN;

In debug mode, UNKNOWN would just be defined to some arbitrary value, like 0. However, when compiling in release mode, I want it to throw an error when UNKNOWN is used, so that unassigned ports don't end up in the final release. I know I can use the #error directive to force an error, but can I do something similar in a macro?

I've seen a solution using static_assert, but I unfortunately can't use C++11 for this platform.

Upvotes: 1

Views: 2371

Answers (4)

Keith Thompson
Keith Thompson

Reputation: 263647

Since #error can't result from a macro expansion, you can ensure that the macro expands to something that must be diagnosed, like a syntax error.

For example:

#ifdef RELEASE
#define UNKNOWN @Invalid_use_of_UNKNOWN
#else
#define UNKNOWN 0
#endif

const int MOTOR_PORT = 1;
const int FAN_PORT = 2;
const int LED_PORT = UNKNOWN;

int main(void) {
    int x = LED_PORT;
}

The @ character isn't part of C's basic character set, so its appearance outside a comment, character constant, or string literal should always result in an error message. ($ would work, except that accepting $ in identifiers is a common extension. ` would probably also work, but @ stands out better.)

I've defined the macro so it produces a reasonable error message with gcc:

c.c:9:1: error: stray ‘@’ in program
c.c:9:22: error: ‘Invalid_use_of_UNKNOWN’ undeclared here (not in a function)

and with clang:

c.c:9:22: error: expected expression
const int LED_PORT = UNKNOWN;
                     ^
c.c:2:17: note: expanded from:
#define UNKNOWN @Invalid_use_of_UNKNOWN
                ^
1 error generated.

(There's a _Pragma operator corresponding to the #pragma directive. It would be nice if there were an _Error operator as well, but there isn't.)

Upvotes: 2

Derek Ledbetter
Derek Ledbetter

Reputation: 4895

The sizeof operator cannot be applied to an incomplete type, so try this:

// Declared, but not defined anywhere.
struct illegal_use_of_unknown_macro;
#define UNKNOWN (sizeof (illegal_use_of_unknown_macro))

Upvotes: 0

dousin
dousin

Reputation: 526

Well, this does not produce a complier error message like #error, but would compile in debug and fail in release:

#ifdef _DEBUG
#   define UNKNOWN 1
#else
#   define UNKNOWN
#endif
const int port1 = UNKNOWN; // fail in release

Upvotes: 1

Sebastian Hoffmann
Sebastian Hoffmann

Reputation: 11502

You could make a division by zero which will throw a compiler error: #define UNKNOWN 0/0

Upvotes: 0

Related Questions