This question already has answers here:
Convert a preprocessor token to a string
(6 answers)
Closed 4 years ago.
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.
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."
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)
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."
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.
Related
I'm writing code in the Arduino (1.6.5) environment. In my code, I want to be able to define a string value, then use it and also Serial.println() it to the serial console.
For example:
#define THEVAL 12345 // Define the value
...
v = v + THEVAL; // Use the value in code.
...
Serial.println("The value is: #THEVAL"); // Show the value to user (for debugging)
However, the compiler doesn't replace constants inside quoted strings. I also tried this (C++ stringification) which indicates that you place the constant outside the quoted string
#define THEVAL 12345
...
Serial.println("This is the value: " #THEVAL);
but that yields a "Stray # character" error in the compiler.
I'd appreciate any insight! Thanks!
EDIT: ODD BEHAVIOR
On testing I discovered the following:
(Note: the IP address uses commas to separate the octets because each octet is passed as a separate parameter to the EthernetServer.begin in a byte array (byte ip[] = { a, b, c, d })
#define IP_ADDRESS 192,168,1,1
#define IP_ADDRESS_STRING(a,b,c,d) xstr(a)"."xstr(b)"."xstr(c)"."xstr(d)
#define xstr(a) str(a)
#define str(a) #a
If I do the following, I get the error "IP_ADDRESS_STRING requires 4 arguments, but only one given"
debug("IP Address is: " IP_ADDRESS_STRING(IP_ADDRESS));
but if I do the following, I get the error "macro 'str' passed 4 arguments, but just takes 1"
debug("IP ADDRESS: " xstr(IP_ADDRESS));
But if I do this, it works:
String ipAddressString(int a, int b, int c, int d)
{
return String(a) + "." + String(b) + "." + String(c) + "." + String(d);
}
debug("IP Address is: " + ipAddressString(IP_ADDRESS));
I'm confused - why does one macro consider IP_ADDRESS to be a single argument, and the other macro sees it as 4 arguments, while the function works correctly: it sees 4 arguments?
#define XSTR(s) STR(s)
#define STR(s) #s
....
#define THEVAL 12345
....
Serial.println("The value of " STR(THEVAL) " is " XSTR(THEVAL));
This would output:
The value of THEVAL is 12345
#define XSTR(s) STR(s)
#define STR(s) #s
....
#define THEVAL 12345
....
Serial.println("The value of " STR(THEVAL) " is " XSTR(THEVAL));
But if THEVAL is set to 123,456 this fails.
With a slight modification it also works:
#define STR(...) #__VA_ARGS__
suggest
Serial.print("This is the value: ");
Serial.println( THEVAL );
or
int x = THEVAL;
Serial.print("This is the value: ");
Serial.println( x );
I'm confused - why does one macro consider IP_ADDRESS to be a single
argument, and the other macro sees it as 4 arguments, while the
function works correctly: it sees 4 arguments?
In the invocation IP_ADDRESS_STRING(IP_ADDRESS), there is obviously only the one argument IP_ADDRESS, and this is true irrespective of how IP_ADDRESS is defined, because argument substitution takes place only after the arguments for the invocation of a function-like macro have been identified (ISO/IEC 9899:201x).
In the invocation xstr(IP_ADDRESS) with the definition #define xstr(a) str(a), according to the above the parameter a is then replaced by the one argument IP_ADDRESS after that macro has been expanded (macro replaced), yielding str(192,168,1,1), so str is passed 4 arguments.
In contrast to the first case, in a function call ipAddressString(IP_ADDRESS) the substitution of IP_ADDRESS takes place not after, but before the arguments for the function call are identified.
You can use the macro by the same two-stage technique that's utilized with xstr()/str():
#define IP_ADDRESS 192,168,1,1
#define XIP_ADDRESS_STRING(abcd) IP_ADDRESS_STRING(abcd)
#define IP_ADDRESS_STRING(a,b,c,d) xstr(a)"."xstr(b)"."xstr(c)"."xstr(d)
#define xstr(a) str(a)
#define str(a) #a
debug("IP Address is: " XIP_ADDRESS_STRING(IP_ADDRESS));
I have a number of definitions consisting of two comma-separated expressions, like this:
#define PIN_ALARM GPIOC,14
I want to pass the second expression of those definitions (14 in the case above) to unary macros like the following:
#define _PIN_MODE_OUTPUT(n) (1U << ((n) * 2U))
How can I extract the second number? I want a macro, call it "PICK_RIGHT", which will do this for me:
#define PICK_RIGHT(???) ???
So that I can make a new macro that can take my "PIN" definitions:
#define PIN_MODE_OUTPUT(???) _PIN_MODE_OUTPUT(PICK_RIGHT(???))
And I can simply do:
#define RESULT PIN_MODE_OUTPUT(PIN_ALARM)
Do not use macros for this. If you must, the following will work by throwing away the left part first so just the number remains. Use with care. No guarantees.
#define PIN_ALARM GPIOC,14
#define RIGHTPART_ONLY(a,b) b
#define PIN_MODE_OUTPUT(a) RIGHTPART_ONLY(a)
#define RESULT PIN_MODE_OUTPUT(PIN_ALARM)
int main (void)
{
printf ("we'll pick ... %d\n", PIN_MODE_OUTPUT(PIN_ALARM));
printf ("or maybe %d\n", RESULT);
return 0;
}
If you want the left part as a string, you can use this (with the same warnings as above), where the left part gets converted to a string by #:
#define LEFTPART_ONLY(a,b) #a
#define PIN_MODE_NAME(a) LEFTPART_ONLY(a)
There is a practical reason this is not entirely without problems. GPIOC is a symbol and as such it is possibly defined elsewhere. Fortunately, it is not a problem if it is undefined, or it is but to a simple type - after all, first thing the macros do is "throw away the left part". But as Jonathan Leffler comments
Note that if GPIOC maps to a macro containing commas, you're likely to get compilation errors.
I need to do some preprocessor magic. Assume that I have a global constant
#define MAX_VALUE 99999
What I need to do is to extract the length of this constant in its decimal representation at compile-time. In other words, I don't want to have another constant
#define MAX_VALUE_STRLEN 5
polluting the global namespace and I don't want to add a place in the code that needs to be changed in the case that MAX_VALUE is modified. If I have a number literal, then I can do something like
#define INTLEN(x) (sizeof(#x)/sizeof((#x)[0]) - 1)
and then INTLEN(99999) would expand to 5 at compile-time. Unfortunately, I can't do something like
INTLEN(MAX_VALUE),
because the preprocessor expands INTLEN first, so that I get
(sizeof("MAX_VALUE")/sizeof(("MAX_VALUE")[0]) - 1)
Is there a preprocessor trick that achieves what I want? Another trickier issue that I should be able to safely ignore is that can this be made generic enough that if someone decides to add a type annotation, say, 99999L to the constant that I can still get the right value?
Stringify using # and two levels of macro expansion, then chop off the terminating NUL:
#define MAX_VALUE 99999
#define STRINGIFY(x) #x
#define LENGTH(x) (sizeof(STRINGIFY(x)) - 1)
#include <stdio.h>
int main()
{
size_t n = LENGTH(MAX_VALUE);
printf("length = %zu\n", n);
return 0;
}
Let's say I have already defined 9 macros from
ABC_1 to ABC_9
If there is another macro XYZ(num) whose objective is to call one of the ABC_{i} based on the value of num, what is a good way to do this? i.e. XYZ(num) should call/return ABC_num.
This is what the concatenation operator ## is for:
#define XYZ(num) ABC_ ## num
Arguments to macros that use concatenation (and are used with the operator) are evaluated differently, however (they aren't evaluated before being used with ##, to allow name-pasting, only in the rescan pass), so if the number is stored in a second macro (or the result of any kind of expansion, rather than a plain literal) you'll need another layer of evaluation:
#define XYZ(num) XYZ_(num)
#define XYZ_(num) ABC_ ## num
In the comments you say that num should be a variable, not a constant. The preprocessor builds compile-time expressions, not dynamic ones, so a macro isn't really going to be very useful here.
If you really wanted XYZ to have a macro definition, you could use something like this:
#define XYZ(num) ((int[]){ \
0, ABC_1, ABC_2, ABC_3, ABC_4, ABC_5, ABC_6, ABC_7, ABC_8, ABC_9 \
}[num])
Assuming ABC_{i} are defined as int values (at any rate they must all be the same type - this applies to any method of dynamically selecting one of them), this selects one with a dynamic num by building a temporary array and selecting from it.
This has no obvious advantages over a completely non-macro solution, though. (Even if you wanted to use macro metaprogramming to generate the list of names, you could still do that in a function or array definition.)
Yes, that's possible, using concatenation. For example:
#define FOO(x, y) BAR ##x(y)
#define BAR1(y) "hello " #y
#define BAR2(y) int y()
#define BAR3(y) return y
FOO(2, main)
{
puts(FOO(1, world));
FOO(3, 0);
}
This becomes:
int main()
{
puts("hello " "world");
return 0;
}
I want a debug function-macro that works like this:
int myVar = 5;
PRINTVAR(myVar); // macro
// which expands to something like...
print("myVar: ");
println(myVar);
Basically, I want to use the identifier as a string literal as well as a variable.
I'm just getting a bit sick of repeating myself when I want to dump out a whole lot of variables to the stdout.
My silly attempt, which of course doesn't work:
#define PRINT_VAR(x) Serial.print("x: "); Serial.println(x);
Is this possible?
The "stringizing operator" is designed for precisely this case:
#define PRINT_VAR(x) (print(#x ": "), println(x))
Look up the stringifying operator, #, when you use the macro id prefixed with this, it puts it as a string instead of expanding it.
Giving your code example, I don't know if you're talking about C or Java. However, here is I'll do in C :
#define DEBUG(X, ...) fprintf(x, __VA_ARGS__);
And to use it :
DEBUG(srderr, "my error\n");