Construct fixed string by concatenating macro with string - c

I've went through a number of similar questions and almost got it to work, but not quite.
What I have is the standard Macro-Expansion-Stringification-method.
#define QUOTEME(M) #M
#define DOQUOTE(M) QUOTEME(M)
#define XCONCAT(X, Y) X##Y
#define CONCAT(X, Y) XCONCAT(X, Y)
Then I have a macro PREFIX like this:
#define SW_PREFIX XY2Ar-
What I was trying to do was:
#define SW_FILE DOQUOTE(CONCAT(SW_PREFIX, update))
What this is supposed to output is: "XY2Ar-update"
What it outputs on my GCC-type compiler is:
error: pasting "-" and "update" does not give a valid preprocessing token
Now, I assume that he's replacing the macro correctly, but apparently doesn't want to append update to XY2Ar- because of the -.
I also tried:
#define SW_FILE DOQUOTE(SW_PREFIX.update)
which, once again, almost does what I want, however it outputs
XY2Ar-.update, which is not what I want either.
I'm out of ideas.

Here is an alternative:
#define QUOTEME(M) #M
#define COMPOSE(A, B) QUOTEME(A) #B
#define SW_PREFIX XY2Ar-
#define SW_FILE COMPOSE(SW_PREFIX, update)

Your thinking seems too complicated :-) Do not create a single token to stringify. Simply use string concatenation for separate parts.
$ cat x.c
#define QUOTEME(M) #M
#define DOQUOTE(M) QUOTEME(M)
#define SW_PREFIX XY2Ar-
#define SW_FILE DOQUOTE(SW_PREFIX) QUOTEME(.update)
char *x = SW_FILE;
$ gcc -E x.c
# 1 "x.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x.c"
char *x = "XY2Ar-" ".update";

Sometimes I keep finding myself forgetting the KISS-principle...and it's times like these where it shows.
#define SW_PREFIX "XY2Ar-"
#define SW_FILE SW_PREFIX"update"
These simple lines, no further expansion or anything return the desired output.
As for the reason why it does that:
Since there aren't any # in there, it expands SW_PREFIX to "XY2Ar-" and appends "update" to it, which results in "XY2Ar-""update", which, for the compiler, is the same as XY2Ar-update.
Thanks to the guy who erased his answers for reminding me.

Related

C Preprocessor: concatenate macro call with token

I'm trying to concatenate a macro call with a token to create a new one, for instance:
#define TEST(X) X ## _TEST
#define CONCAT(X) TEST(X) ## _CONCAT
CONCAT(OK);
Then I check the output with gcc -E; I would want to get OK_TEST_CONCAT; but instead I get an error:
error: pasting ")" and "_CONCAT" does not give a valid preprocessing token
If I remove ## I get no error but the output is OK_TEST _CONCAT;
This is a minimal example, so the easiest here would be to combine everything in a single macro, but know that it's impossible for me to get rid of the first call to TEST. Is there a way to remove that space?
Thanks
EDIT:
Ok so from the confusion maybe my example was a little too minimal, that's my fault. Here is a more plausible use case:
I want all the prototypes in a certain header to be prefixed by the PREFIX defined in that header.
proto.h:
#define EXPAND(X) EXPAND_HELPER(X)
#define EXPAND_HELPER(X) X
#define PROTO(NAME) PREFIX ## NAME
other.h:
#include <proto.h>
#define PREFIX other
int PROTO(test)(int a, int b);
...
What I want is all the prototypes in other.h to have this form: int other_test(int a, int b);. But as it is they have this form: int PREFIX_test(int a, int b);. After googling I found that I needed to force PREFIX to rescan, so I tried this:
#define PROTO(NAME) EXPAND(PREFIX) ## NAME
which prompted my question. Now if I look at #Lundin's answer, I can adapt it to give what I want:
Solution:
#define PROTO(NAME) PROTO_HELPER(PREFIX, NAME)
#define PROTO_HELPER(PREFIX, NAME) PROTO_EXPAND(PREFIX, NAME)
#define PROTO_EXPAND(PREFIX, NAME) PREFIX ## NAME
Thanks!
All preprocessor tokens must be expanded before a function-like macro using ## or # is called. Because ## or # is applied before macro expansion. In your case TEST(X) only expands X into TEST(OK) and then the preprocessor attempts to paste TEST(OK) with _CONCAT which won't work. For each attempt to concatenate tokens, you must first expand all macros before ##, which is done by extra helper macros that force a rescanning/replacement.
The contrived solution given #define TEST(X) X ## _TEST would be this:
#define CONCAT(X) EXPAND_HELPER(TEST(X)) // expands TEST(X) to TEST(OK)
-->
#define EXPAND_HELPER(X) CONCAT_HELPER(X, _CONCAT) // expands TEST(OK) to OK_TEST
-->
#define CONCAT_HELPER(X,Y) X ## Y
That is:
// NOTE: contrived solution, avoid
#define TEST(X) X ## _TEST
#define CONCAT_HELPER(X,Y) X ## Y
#define EXPAND_HELPER(X) CONCAT_HELPER(X, _CONCAT)
#define CONCAT(X) EXPAND_HELPER(TEST(X))
...
int CONCAT(OK) = 1; // becomes int OK_TEST_CONCAT = 1;
A much simpler solution would be:
#define CONCAT(X) X ## _TEST ## _CONCAT

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

macro expansion to additional macro arguments

I'm looking for a way of making a macro that expands to extra arguments:
int constant1=2, constant2=3;
#define add_three_arguments(x,y,z) x+y+z
#define extra_arguments ,constant1,constant2
#define make_value(A) add_three_arguments(A extra_arguments)
int r = make_value(5);
The closest solution I have found is this:
int constant1=2, constant2=3;
#define _add_three_arguments(x,y,z) x+y+z
#define add_three_arguments(...) _add_three_arguments(__VA_ARGS__)
#define extra_arguments ,constant1,constant2
#define make_value(A) add_three_arguments(A extra_arguments)
int r = make_value(5);
Which is of course not a solution to the problem I stated. So the current answer seems to be, "this is not possible." But maybe a new version of clang/gcc will somehow enable this. I will leave the question open.
Try the following:
#define EMPTY
#define EVAL(X) X
#define add_three_arguments(x,y,z) x+y+z
#define extra_arguments ,constant1,constant2
#define make_value(A) EVAL(add_three_arguments EMPTY (A extra_arguments))
make_value(5);
However, if you redesign your macros you may get a nicer solution not requiring such constructs.

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);

C Preprocessor, Stringify the result of a macro

I want to stringify the result of a macro expansion.
I've tried with the following:
#define QUOTE(str) #str
#define TEST thisisatest
#define TESTE QUOTE(TEST)
And TESTE gets expanded to: "TEST", while I'm trying to get "thisisatest". I know this is the correct behavior of the preprocessor but can anyone help me with a way to achieve the other one?
Using TESTE #TEST is not valid
Using TESTE QUOTE(thisisatest) is not what I'm trying to do
Like this:
#include <stdio.h>
#define QUOTE(str) #str
#define EXPAND_AND_QUOTE(str) QUOTE(str)
#define TEST thisisatest
#define TESTE EXPAND_AND_QUOTE(TEST)
int main() {
printf(TESTE);
}
The reason is that when macro arguments are substituted into the macro body, they are expanded unless they appear with the # or ## preprocessor operators in that macro. So, str (with value TEST in your code) isn't expanded in QUOTE, but it is expanded in EXPAND_AND_QUOTE.
To clarify a bit more, essentially the preprocessor was made to execute another "stage". i.e :
1st case:
->TESTE
->QUOTE(TEST) # preprocessor encounters QUOTE
# first so it expands it *without expanding its argument*
# as the '#' symbol is used
->TEST
2nd case:
->TESTE
->EXPAND_AND_QUOTE(TEST)
->QUOTE(thisisatest)
# after expanding EXPAND_AND_QUOTE
# in the previous line
# the preprocessor checked for more macros
# to expand, it found TEST and expanded it
# to 'thisisatest'
->thisisatest

Resources