1

How can I use another macro in a string macro in C?

I have this:

#define MAX_OPERATION_COUNT 10
#define MSG_TOO_MANY_OPERATIONS "Too many operations! Only the first 10 were applied."

But I would like the second macro to use the value of the first one instead. In Java for instance, I would have had something like:

public static final int MAX_OPERATION_COUNT = 10;
public static final String MSG_TOO_MANY_OPERATIONS = "Too many operations! Only the first " + MAX_OPERATION_COUNT + " were applied.";

Is there a way to do something similar in C?

Edit: The solution to this turned out to be very similar to the solution to this question, but I believe the problem itself is quite different and should be treated separately.

SakoDaemon
  • 973
  • 1
  • 6
  • 21

4 Answers4

9

Usually it's easier to deal with printf-style formatting, kind of "Too many operations! Only the first %u were applied". However, if you really want to make string substitution you have to do it twice:

#define STR(x) STR2(x)
#define STR2(x) #x
#define MAX_OPERATION_COUNT 10
#define MSG_TOO_MANY_OPERATIONS "Too many operations! Only the first " STR(MAX_OPERATION_COUNT) " were applied."
Matt
  • 13,674
  • 1
  • 18
  • 27
  • Thank you, this is perfect. Out of curiosity, how would the printf-style formatting solution look like? Do you mean creating a function macro? – SakoDaemon Oct 08 '18 at 11:53
  • 1
    @SakoDaemon: "*how would the printf-style formatting solution look like*" Unfortunately in global scope this would not be possible at all. As in global scope no function calls were possible. – alk Oct 08 '18 at 11:54
  • @alk: Fair point, thank you. – SakoDaemon Oct 08 '18 at 11:56
1

You could "parametrise" the 2nd macro:

#define STRINGYFY(x) # x
#define PASTE_AS_STRING(s) STRINGYFY(s)

#define MAX_OPERATION_COUNT 10
#define MANY_OPERATION_COUNT 2

#define MSG_TOO_MANY_OPERATIONS_TEMPLATE(n) \
  "Too many operations! Only the first" PASTE_AS_STRING(n) " were applied."

#define MSG_TOO_MANY_OPERATIONS \
  MSG_TOO_MANY_OPERATIONS_TEMPLATE(MAX_OPERATION_COUNT)
#define MSG_MUCH_TOO_MANY_OPERATIONS \
  MSG_TOO_MANY_OPERATIONS_TEMPLATE(MANY_OPERATION_COUNT)

(Just saw Matt's answer, being more or less the same, but elder. Still, I leave this in here, as I feel this approach uses a slightly different structure.)


You could as well define variables and use the macros just only to initialise them.

To define arrays do

const char MSG_TOO_MANY_OPERATIONS[] = 
  MSG_TOO_MANY_OPERATIONS_TEMPLATE(MAX_OPERATION_COUNT)
const char MSG_MUCH_TOO_MANY_OPERATIONS[] =
  MSG_TOO_MANY_OPERATIONS_TEMPLATE(MANY_OPERATION_COUNT)

or to define pointers do

const char * MSG_TOO_MANY_OPERATIONS = 
  MSG_TOO_MANY_OPERATIONS_TEMPLATE(MAX_OPERATION_COUNT)
const char * MSG_MUCH_TOO_MANY_OPERATIONS =
  MSG_TOO_MANY_OPERATIONS_TEMPLATE(MANY_OPERATION_COUNT)
alk
  • 69,737
  • 10
  • 105
  • 255
0

You can do:

#define FOO "1"
#define BAR "How many foos? " FOO " foo.\n"

BAR now expands to

"How many foos? " "1" " foo.\n" 

which is a valid string literal.

nullp0tr
  • 485
  • 3
  • 11
  • 2
    Just a side note: Yes, this will expand. But something tells me, there might be this sort of condition somewhere in code : `if (foo_count < FOO) printf("%s", BAR)` – Igor S.K. Oct 08 '18 at 11:32
0

You need to make number 10 a string. Then, in order to "concatenate" the strings, you would just close the double quotes, insert your macro that represents the number, and then simply open double quotes again (no need for any plus operator like in Java/C++ for a string), to write the rest of the message, like this:

#define MAX_OPERATION_COUNT "10"
#define MSG_TOO_MANY_OPERATIONS "Too many operations! Only the first " MAX_OPERATION_COUNT " were applied."
gsamaras
  • 71,951
  • 46
  • 188
  • 305