views:

36

answers:

2

I'm developing an embedded application in C99, and the project contains some integer constants defined like:

#define LEVEL1     0x0000
#define LEVEL2     (LEVEL1 + 1)

It has since become useful to keep track of these values for logging purposes, so I would like to use a macro to create a string literal from the evaluated versions of the above. For example:

strncpy(str, STRING(LEVEL2), len);

would ideally evaluate to

strncpy(str, "0x0001", len);

or even

strncpy(str, "0001", len);

Using a two-stage macro with the # operator (as suggested by this question) almost works. It evaluates to

strncpy(str, "(LEVEL1 + 1)", len);

I would like to avoid the use of a run-time function - hence my attempt at a macro solution. Suggestions?

+1  A: 

Since the pre-processor stringizer is a massive pain, you need to add a level of indirection both when creating version numbers and when stringizing:

#define STRING1(s) #s
#define STRING(s) STRING1(s)

#define LEVEL(x) x
#define LEVEL1 LEVEL(1)
#define LEVEL2 LEVEL(2)

printf(STRING(LEVEL2));
//2
Igor Zevaka
+1  A: 

You cannot do this because the preprocessor knows nothing about the C language so it cannot to evaluation.

I see two options to get the desired result:

Manual evaluation

Write your levels exactly as you want them to appear and use a single stringizer operator:

#define LEVEL1 0x0000
#define LEVEL2 0x0001
#define STRING(x)   # x

strncpy(str, STRING(LEVEL2), len);

A disadvantage is that this is error prone and might clash with local coding conventions.

Runtime evaluation

Use one of the string format functions sprintf or snprintf.

#define LEVEL1 0x0000
#define LEVEL2 0x0001

char level[7];
snprintf(level, sizeof level, "%#06x", LEVEL2);
strncpy(str, level, len);

This has the runtime overhead you wanted to avoid.

schot