3
\$\begingroup\$

I maintain a C library project both on gcc and clang.

I am looking for advice on how to make the following macros more portable, terse, readable or standard abiding.

When I compile

#define STRINGIFY(arg) STRINGIFY_(arg)
#define STRINGIFY_(arg) #arg

#define VERSION 1.01
#define PROJECT myProject
#define SUB_PROJECT mySub
#define DASH -

#include STRINGIFY(PROJECT DASH SUB_PROJECT DASH VERSION.c)

I get

clang 6.0.0 standard C99

myProject - mySub - 1.01.c

gcc 7.4.0 standard C99

myProject-mySub-1.01.c

I came up with the following solution

#define STRINGIFY(arg) STRINGIFY_(arg)
#define STRINGIFY_(arg) #arg
#define ID(arg) arg

#define VERSION 1.01
#define PROJECT myProject
#define LIB myLib
#define DASH -
#define DOTC .c

#define FILEVERSION(a, b, c, d, e) STRINGIFY(ID(a)ID(b)ID(c)ID(d)ID(e)ID(DOTC))

#include FILEVERSION(PROJECT, DASH, LIB, DASH, VERSION)
\$\endgroup\$
2
\$\begingroup\$

I think this is beyond the jurisdiction of the C standard. See https://stackoverflow.com/questions/37796947/spaces-inserted-by-the-c-preprocessor. All the standard says on the topic is a footnote:

Note that adjacent string literals are not concatenated into a single string literal (see the translation phases in 5.1.1.2); thus, an expansion that results in two string literals is an invalid directive.

https://port70.net/~nsz/c/c11/n1570.html#note170

But this doesn't really matter since you are not making multiply strings.


Investigating GCC and Clang...

GCC does different things depending on what you ask for:

STRINGIFY(PROJECT DASH SUB_PROJECT DASH VERSION.c)

... gets me "myProject - mySub - 1.01.c" with GCC 9.3 and -E, but ...

#include STRINGIFY(PROJECT DASH SUB_PROJECT DASH VERSION.c)

gets me myProject-mySub-1.01.c: No such file or directory. So -E has spaces and #include doesn't.

Clang is at least consistent. With Clang 10, #include has spaces: fatal error: 'myProject - mySub - 1.01.c' file not found And Clang 10 and -E also has spaces myProject - mySub - 1.01.c.

In my opinion, Clang's behavior makes the most sense. Suppose you wanted a space -- how else could you do that?


#define ID(arg) arg

This is a common trick. I think it's a good idea although it looks a little ugly when you have to use it in so many spots.


#define STRINGIFY(arg) STRINGIFY_(arg)
#define STRINGIFY_(arg) #arg

This is fine, but I think it'd be clearer to define STRINGIFY below the helper macro it uses.


Can you get away with something like:

#if VERSION == 1
#include "library-version-1.h"
#else
#include "library-version-other.h"
#endif
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.