Concatenate int to string using C Preprocessor - c

I'm trying to figure out how I can concatenate a #define'd int to a #define'd string using the C Preprocessor. My compiler is GCC 4.1 on CentOS 5. The solution should also work for MinGW.
I'd like to append a version number onto a string, but the only way I can get it to work is to make a copy of the version number defines as strings.
The closest thing I could find was a method of quoting macro arguments, but it doesn't work for #defines
This is does not work.
#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" #MAJOR_VER #MINOR_VER
It doesn't work without the #s either because the values are numbers and it would expand to "/home/user/.myapp" 2 6, which isn't valid C.
This does work, but I don't like having copies of the version defines because I do need them as numbers as well.
#define MAJOR_VER 2
#define MINOR_VER 6
#define MAJOR_VER_STR "2"
#define MINOR_VER_STR "6"
#define MY_FILE "/home/user/.myapp" MAJOR_VER_STRING MINOR_VER_STRING

Classical C preprocessor question....
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" STR(MAJOR_VER) STR(MINOR_VER)
The extra level of indirection will allow the preprocessor to expand the macros before they are converted to strings.

A working way is to write MY_FILE as a parametric macro:
#define MY_FILE(x,y) "/home..." #x #y
EDIT: As noted by "Lindydancer", this solution doesn't expand macros in arguments. A more general solution is:
#define MY_FILE_(x,y) "/home..." #x #y
#define MY_FILE(x,y) MY_FILE_(x,y)

You can do that with BOOST_PP_STRINGIZE:
#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" BOOST_PP_STRINGIZE(MAJOR_VER) BOOST_PP_STRINGIZE(MINOR_VER)

Related

Can C-preprocessor can output as a string the evaluation of compiled known constants values(e.g. 150000UL/1000UL)? #define arithmetics

I'm wondering if it can be written that the prepocessor evaluates assigned constants known at compile time and returns the result as a string. I believe the answer is no or complex, but I'll give a try.
Basically I have constants which are expressed in milliseconds but I want to display the results as secs, therefore divide by 1000, and wonder because all is known at compile time, if the preprocessor can directly put the result of this division into the code rather than eval at runtime.
Example:
#define FREQ_AUTO_WHEN_RELAY_ON 150000UL
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
STR( FREQ_AUTO_WHEN_RELAY_ON/1000UL ) " secs"
would yield to "150000UL/1000UL secs"
which is not I want to display, aka "150 secs"
Thanks
You have to first prepare a header with all possible outputs:
// calculate.h
#if VALUE == 1
#define RESULT 1
#elif VALUE == 2
#define RESULT 2
/* etc. millions of lines */
#elif VALUE == 150
#define RESULT 150
#endif
Then you can do:
#define VALUE FREQ_AUTO_WHEN_RELAY_ON/1000UL
#include "calculate.h"
STR(VALUE)
Similarly, you first have to define a matrix of all possible combinations of values:
#define DIV_1UL_1UL 1
#define DIV_1UL_2UL 0
#define DIV_2UL_1UL 2
/* etc. really millions of lines */
#define DIV_150000UL_1000UL 150
Then you can:
#define DIV(a, b) DIV_##a##_##b
#define XDIV(a, b) DIV(a, b)
STR(XDIV(FREQ_AUTO_WHEN_RELAY_ON, 1000UL))
Can C-preprocessor can output as a string the evaluation of compiled known constants values(e.g. 150000UL/1000UL)?
Yes, but it's not practical. Instead, generate the header file from a build system.

How do I concatenate two string macros in C?

I am trying to implement VERSION macro for my program, that is to be changed under certain circumstances.
macro VERSION is defined via Makefile (git info is put there) and is a string.
Now I have a set of #define'd switches and I want VERSION to reflect which of them are on. This looks now like the follows (main.h):
#define COMPLEX_DEPOSITION // This is switch. later in code it is used in #ifdef...#endif construction.
#ifdef COMPLEX_DEPOSITION
#define CD "_COMP_DEP" // this is the string I want to put in the end of VERSION
#define VERSION_ VERSION CD
#undef VERSION // this is to suppress 'macro redefinition' warning
#define VERSION VERSION_
#undef VERSION_
#endif
Well, I get a lot of errors, most of which make me think that C preprocessor works with lines in file in random order:(
Later I have an even more complex thing that is intended to make VERSION -> VERSION_WLT_GAP_2
#define WIRESLIFETIMES
#ifdef WIRESLIFETIMES
#define GAP 2
#define VERSION_ (VERSION ## "_WLT_GAP_" ## #GAP)
#define VERSION VERSION_
#undef VERSION_
#endif
and I got no idea what to do and if this is even possible
String literals concatenate naturally when placed next to each other
"foo" "bar" is the same as "foobar".
As for the second example, you probably want:
#define CAT_(A,B) A##B
#define CAT(A,B) CAT_(A,B)
#define GAP 2
#define VERSION CAT(VERSION_WLT_GAP_ , GAP)
VERSION //expands to VERSION_WLT_GAP_2
I recommend playing with gcc -E/clang -E a bit, to learn how macros work,
before trying to compose anything complex with them.
Well, the answer seems to be the following:
// https://stackoverflow.com/questions/5256313/c-c-macro-string-concatenation
// Concatenate preprocessor tokens A and B without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded).
#define PPCAT_NX(A, B) A ## B
// Concatenate preprocessor tokens A and B after macro-expanding them.
#define PPCAT(A, B) PPCAT_NX(A, B)
// Turn A into a string literal without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded).
#define STRINGIZE_NX(A) #A
// Turn A into a string literal after macro-expanding it.
#define STR(A) STRINGIZE_NX(A)
#define COMPLEX_DEPOSITION
#ifdef COMPLEX_DEPOSITION
#define CD "_COMPDEP"
#else
#define CD ""
#endif
#define WIRESLIFETIMES
#ifdef WIRESLIFETIMES
#define GAP 2
#define WLT STR(PPCAT(_WLT:G, GAP))
#define DISABLE_METROPOLIS
#else
#define WLT ""
#endif
#define VERSION VERSIONX CD WLT
which produces V008.1-11-g68a9c89cb4-dirty_COMPDEP_WLT:G2 and I am happy with it.
Must be noted that I changed -DVERSION=... to -DVERSIONX=... inside Makefile

C Preprocessor: Stringify int with leading zeros?

I've seen this topic which describes the "stringify" operation by doing:
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" STR(MAJOR_VER) STR(MINOR_VER)
Is it possible to stringify with leading zeros? Let's say my MAJOR_REV needs to be two characters "02" in this case and MINOR_REV 4 characters "0006"
If I do:
#define MAJOR_VER 02
#define MINOR_VER 0006
The values will be treated as octal elsewhere in the application, which I don't want.
No clean nor handy way to do it. Just as a challenge, here a possible "solution":
1) create a header file (e.g. "smartver.h") containing:
#undef SMARTVER_HELPER_
#undef RESVER
#if VER < 10
#define SMARTVER_HELPER_(x) 000 ## x
#elif VER < 100
#define SMARTVER_HELPER_(x) 00 ## x
#elif VER < 1000
#define SMARTVER_HELPER_(x) 0 ## x
#else
#define SMARTVER_HELPER_(x) x
#endif
#define RESVER(x) SMARTVER_HELPER_(x)
2) In your source code, wherever you need a version number with leading zeroes:
#undef VER
#define VER ...your version number...
#include "smartver.h"
at this point, the expression RESVER(VER) is expanded as a four-digit sequence of character, and the expression STR(RESVER(VER)) is the equivalent string (NOTE: I have used the STR macro you posted in you answer).
The previous code matches the case of minor version in your example,it's trivial to modify it to match the "major version" case. But in truth I would use a simple external tool to produce the required strings.
I believe in the example provided by the question sprintf is the correct answer.
That said, there are a few instances where you really want to do this and with C preprocessor if there is a will and somebody stupid enough to write the code there is typically a way.
I wrote the macro FORMAT_3_ZERO(a) which creates a three digit zero padded number using brute force. It is in the file preprocessor_format_zero.h found at https://gist.github.com/lod/cd4c710053e0aeb67281158bfe85aeef as it is too large and ugly to inline.
Example usage
#include "preprocessor_format_zero.h"
#define CONCAT_(a,b) a#b
#define CONCAT(a,b) CONCAT_(a,b)
#define CUSTOM_PACK(a) cp_ ## a __attribute__( \
(section(CONCAT(".cpack.", FORMAT_3_ZERO(a))), \
aligned(1), used))
const int CUSTOM_PACK(23);

Stringify first level macro expansion C

Is it possible to stringify this C macro:
#define GPIO_INT_PIN (GPIO_PORT_D|GPIO_PIN_IRQ_RISING|GPIO_PIN5)
using something like
MY_STRINGFY(GPIO_INT_PIN)
to get
"(GPIO_PORT_D|GPIO_PIN_IRQ_RISING|GPIO_PIN5)" ?
Yes it is possible. Read about stringizing in GCC cpp documentation.
#define STRINGIFY(It) #It
#define MY_STRINGIFY(It) STRINGIFY(It)
I corrected my answer thanks to Wojtek Surowka's one
then use MY_STRINGIFY(GPIO_PORT_D|GPIO_PIN_IRQ_RISING|GPIO_PIN5) which would work much better if you use an enum to define the constants, e.g.
enum Gpio_stuff_en {
GPIO_PORT_D=5,
GPIO_PIN_IRQ_RISING=17,
GPIO_PIN5=23
};
Of course that won't work as you want if you need GPIO_PORT_D to be a macro, .e.g. because it expands to some non-constant-literal expression (like a variable, or an access to a field of some global structure, etc....)
As a counter-example:
#define FOO 1
#define BAR 2
#define STRINGIFY(s) #s
#define MY_STRINGIFY(s) STRINGIFY(s)
MY_STRINGIFY(FOO|BAR)
is expanded to "1|2" not to "FOO|BAR", if your remove the two #define-s for FOO and for BAR and replace them with
enum {
FOO=1,
BAR=2 };
you really get the expansion "FOO|BAR" as you want. Check with gcc -C -E ...
Also:
enum {FOO=1, BAR=2};
#define FOOORBAR (FOO|BAR)
#define STRINGIFY(s) #s
#define MY_STRINGIFY(s) STRINGIFY(s)
MY_STRINGIFY(FOOORBAR)
is expanded as "(FOO|BAR)" . But if you use #define for FOO and for BAR you get the "(1|2)" expansion.
Maybe you could add in your own header, after including the external header defining GPIO_PORT_D etc... as a literal constants, something like :
enum {en_GPIO_PORT_D= GPIO_PORT_D,
en_GPIO_PIN_IRQ_RISING= GPIO_PIN_IRQ_RISING,
en_GPIO_PIN5= GPIO_PIN5};
#undef GPIO_PORT_D
#undef GPIO_PIN_IRQ_RISING
#undef GPIO_PIN5
#define GPIO_PORT_D en_GPIO_PORT_D
#define GPIO_PIN_IRQ_RISING en_GPIO_PIN_IRQ_RISING
#define GPIO_PIN5 en_GPIO_PIN5
and then you'll get more readable stringified constants (but not exactly what you dream of).
If you have such two definitions
#define STRINGIFY(s) #s
#define MY_STRINGIFY(s) STRINGIFY(s)
MY_STRINGIFY does what you want - expands its argument and adds quotes after.

How to escape an underscore in a C preprocessor token?

The following snippet is supposed to take the value of PROJECT (defined in the Makefile)
and create an include file name. For example, if PROJECT=classifier, then it should at the end generate classifier_ir.h for PROJECTINCSTR
I find that this code works as long as I am not trying to use an underscore in the suffix. However the use of the underscore is not optional - our code base uses them everywhere. I can work around this because there are a limited number of values for PROJECT but I would like to know how to make the following snippet actually work, with the underscore. Can it be escaped?
#define PROJECT classifier
#define QMAKESTR(x) #x
#define MAKESTR(x) QMAKESTR(x)
#define MAKEINC(x) x ## _ir.h
#define PROJECTINC MAKEINC(PROJECT)
#define PROJECTINCSTR MAKESTR(PROJECTINC)
#include PROJECTINCSTR
Edit: The compiler should try to include classifier_ir.h, not PROJECT_ir.h.
#define QMAKESTR(x) #x
#define MAKESTR(x) QMAKESTR(x)
#define SMASH(x,y) x##y
#define MAKEINC(x) SMASH(x,_ir.h)
#define PROJECTINC MAKEINC(PROJECT)
#define PROJECTINCSTR MAKESTR(PROJECTINC)
This works for me:
#define QMAKESTR(x) #x
#define MAKESTR(x) QMAKESTR(x)
#define MAKEINC(x) x ## _ir.h
#define PROJECTINC(x) MAKEINC(x)
#define PROJECTINCSTR MAKESTR(PROJECTINC(PROJECT))
#include PROJECTINCSTR
That barebone example works with gcc (v4.1.2) and tries to include "PROJECT_ir.h"

Resources