Arduino: How to print out value of defined constants? - c

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

Related

Using macros inside a printf string in C?

Given 3 doubles x, y and z, I make a lot of such printf calls:
printf("[%+-8.3lf, %+-8.3lf, %+-8.3lf]\n", x, y, z);
I then would like to have a macro of some sort to write something like this:
#define FORMAT(x,y) "+-x.ylf"
printf("[%FORMAT(8,3), %FORMAT(8,3), %FORMAT(8,3)]\n", a->x, a->y, a->z);
But of course, the compiler sees %F as a special string and doesn't get my macro inside the string.
Is there a way to achieve what I want ?
Using simple numbers as arguments to FORMAT
Your "something like this" code is close — but you need to use string concatenation (of adjacent string literals) and the # operator to 'stringize' macro arguments:
#define FORMAT(x,y) "%+-" #x "." #y "lf"
printf("[" FORMAT(8,3) ", " FORMAT(8,3) ", " FORMAT(8,3) "]\n",
a->x, a->y, a->z);
This is similar to using the macros from <inttypes.h> for printing types such as int64_t, except with those, you have to provide the % symbol (and any flags):
uint64_t x = 0x43218765CBA9;
printf("x = 0x%.12" PRIX64 "\n", x);
Using macros as arguments to FORMAT
Would there be a way to define my 8 and 3 values as macros too? Like instead of writing everywhere FORMAT(8,3), I would like to write FORMAT(X, Y) where I defined above #define X 8 and #define Y 3.
Yes, there is a way to do that. Introduce an extra macro:
#define STR(z) #z
And invoke that on the arguments to FORMAT, as shown here:
/* SO 7531-4669 */
#include <stdio.h>
#define STR(z) #z
#define FORMAT(x,y) "%+-" STR(x) "." STR(y) "lf"
#define Y 4
#define X 8
struct Point { double x, y, z; };
int main(void)
{
struct Point b = { 7123.4567, 6234.5678, 5345.6789 };
struct Point *a = &b;
printf("[" FORMAT(X, Y) ", " FORMAT(X, Y) ", " FORMAT(X, Y) "]\n",
a->x, a->y, a->z);
printf("[" FORMAT(8, 3) ", " FORMAT(8, 3) ", " FORMAT(8, 3) "]\n",
a->x, a->y, a->z);
return 0;
}
This works and produces the output:
[+7123.4567, +6234.5678, +5345.6789]
[+7123.457, +6234.568, +5345.679]
It demonstrates that you can use simple numbers or macros that map to simple numbers as the arguments to this FORMAT macro. What you can't do is have #define Y 3 and #define X (Y + 6) — that will stringify (3 + 6) which isn't valid in a printf() conversion specification. (Beware of making X too big; you can end up with spaces between your number and the following comma. Experiment with #define X 12 to see what I mean.)
The technique of invoking another macro triggers the expansion of the argument, which is often what you want. See How to make a char string from a C macro's value? and Macro directives in C — my code example doesn't work. The Q&A How can I concatenate twice with the C preprocessor and expand a macro as in "arg ## _ ## MACRO"? is about token concatenation rather than stringification, but the issues are closely related, and the solutions are similar.
You could adjust the macro to something like:
#define SPEC "lf"
#define FORMAT(x, y) "+-"#x"."#y SPEC
and call printf :
printf("%"FORMAT(3, 20), x)
It might also be a good idea to place % inside the macro.
The single hash (#), "converts" x and y arguments to string literals.
Example

Get the value of a macro using a string with macro name

I have a set of macro definitions that the name only change on the number between "C_" and "_E". What I need is a macro that gets a integer variable and returns the integer value of the corresponding macro definition in case it exists, if it does not exist, it returns "-1" or gives a compile error. Is that possible? The code I need is something like this:
#include <stdio.h>
#define C_1_E 4
#define C_2_E 2
#define C_3_E 0
#define C_4_E 420
#define STR(x) #x
#define STR_MACRO(x) "C_" STR(x) "_E"
#define MACRO_VAL(x) ... // return the value of the macro C_x_E when x=1,2,3 or 4
void main() {
uint8_t n;
for(n=1;n<=4;n++) printf("val %u: %u\n",n, MACRO_VAL(STR_MACRO(n)));
}
Expected output:
val 1: 4
val 2: 2
val 3: 0
val 4: 420
According to my search, this is not possible, but I can swear I did cross this solution once, but I didn't need it back then although I thought it could be helpful.
If you need to have a macro specifically, not a function, then it must be that a macro that expands to a function call is not acceptable either. That makes sense to me only if you need the conversion of macro number to macro expansion to be performed at compile time, by the preprocessor. That doesn't appear to be a necessity for the example code, but there are cases where it would indeed be needed.
And that's too bad, because the C preprocessor then provides no way to achieve what you ask. Variables do not exist or have values at compile time, so there is no way at compile time for the compiler to convert a variable name to the value it represents, much less to build a macro name out of it, much less to expand such a name to its replacement text.
You could, however, do it with numeric literals instead of a variable:
#define EXPAND(x) x
#define MACRO_VAL(n) EXPAND(C_ ## n ## _E)
printf("val %d: %d\n",n, 1, MACRO_VAL(1));
printf("val %d: %d\n",n, 2, MACRO_VAL(2));
printf("val %d: %d\n",n, 3, MACRO_VAL(3));
printf("val %d: %d\n",n, 4, MACRO_VAL(4));
If you try to expand that with an argument that does not produce the name of a defined macro or in-scope variable then that (almost surely) will produce a compile-time error for a reference to an undefined variable.
If run-time evaluation were acceptable after all, then you could write a function that does it (which you could wrap in a macro if you wanted):
#define MACRO_VAL(n) lookup_macro(n)
#define EXPAND(x) x
#define MACRO_CASE(i) case i: return EXPAND(C_ ## i ## _E)
int lookup_macro(int n) {
switch (n) {
MACRO_CASE(1);
MACRO_CASE(2);
MACRO_CASE(3);
MACRO_CASE(4);
default: return -1;
}
}
That will return -1 for an arithmetic argument that is not covered by the defined cases.
You could also consider a lookup table, possibly wrapped in a function, but that would require somewhat more code to provide a -1 result in the event of an argument that doesn't match any macro, especially if the macro numbers are not all consecutive or if the least of them is not known in advance.
Token pasting approaches are inappropriate as x is a variable name.
Here is a simplistic approach that will work as long as the macro argument is an expression without side effects:
#include <stdio.h>
#define C_1_E 4
#define C_2_E 2
#define C_3_E 0
#define C_4_E 420
// return the value of the macro C_x_E when x=1,2,3 or 4
#define MACRO_VAL(x) ((x) == 1 ? C_1_E : \
(x) == 2 ? C_2_E : \
(x) == 3 ? C_3_E : \
(x) == 4 ? C_4_E : -1)
int main() {
int n;
for (n = 1; n <= 4; n++)
printf("val %u: %u\n", n, MACRO_VAL(n));
return 0;
}

variadic macro that handles last argument in a different way

I was wandering if there is a way to define a variadic macro that handles its last argument in a different way.
For example, can I define a macro that prints a custom separator after every argument except for the last one?
i.e. how to define MACRO:
MACRO(a, lot, of, bars)
In order to produce this output:
a|lot|of|bars
(EDIT: it was pointed out to me by the comments that the case of , as separator is trivial)
You can apply the macro argument counting trick. For up to five macro arguments (the original answer supported 4 macro arguments, so you can view the diff to see how to extend the macro for additional arguments):
#define MACRO(...) MACRO_X(__VA_ARGS__,5,4,3,2,1)(__VA_ARGS__)
#define MACRO_X(_5,_4,_3,_2,_1,X,...) MACRO_##X
#define MACRO_5(X,...) X|MACRO_4(__VA_ARGS__)
#define MACRO_4(X,...) X|MACRO_3(__VA_ARGS__)
#define MACRO_3(X,...) X|MACRO_2(__VA_ARGS__)
#define MACRO_2(X,...) X|MACRO_1(__VA_ARGS__)
#define MACRO_1(X,...) X
To create a string, you can use the "stringify" operator:
#define STR2(X) STR(X)
#define STR(X) #X
So:
puts(STR2(MACRO(a,lot,of,bars)));
If the output does not need to be stringised, then you can produce an equivalent expression relatively simply:
#define MACRO(...) BIGMACRO(__VA_ARGS__,0,0,0,0,0,0,0,0)
#define BIGMACRO(a0,a1,a2,a3,a4,a5,a6,a7,...) a0|a1|a2|a3|a4|a5|a6|a7
so MACRO(a,lot,of,bars) expands to a|lot|of|bars|0|0|0|0 , which has the same type and value as a|lot|of|bars.

Using a string macro in another macro [duplicate]

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.

Extract Argument from C Macro

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.

Resources