how to make macro replacement text into a string in C / C++ - c-preprocessor

I wonder if it is possible to create a string literal containing the replacement text of a preprocessor macro.
E. g. one has defined:
#define Number 2.847
And the program is supposed to output this number as a string. I tried:
#define M(a) #a
int main() {
cout << M(Number) << endl;
}
But it outputs "Number" instead of "2.847".
Is there a way to make it work without changing the definition of Number? Since this definition might be in a standard header which does not even exist as a file.

You have to do another pass. Typically:
#include <iostream>
#define NUMBER 2.847
#define STRING(a) #a
#define XSTRING(a) STRING(a)
int main() {
std::cout << XSTRING(NUMBER) << '\n';
}

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

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.

Printing the variable identifier formed by the preprocessor

How to retrieve the text expanded from a macro?
#include <stdio.h>
#define paste(front, back) front ## back
int main()
{
int number1 = 23;
int number2 = 64;
printf("%d\n", paste(number, 2));
return 0;
}
The output is: 64 because the macro is expanded as:
printf("%d\n", number2);
How can I print the identifier number2 as string by using the defined paste macro. I need to know how to create the output:
number2: 64 by not writing directly "number2" I don't want this solution:
printf("number2: %d\n", paste(number, 2))
I want a dynamic solution. I try to concatenate by doing:
printf("%s: %d\n", paste(number, 2), paste(number, 2));
But it doesn't work because number2 returned by the paste macro is an the identifier an integer How can I retrieve as a text (string)?
Use the stringizing directive #:
#define stringize_impl(x) #x
#define stringize(x) stringize_impl(x)
printf("%s: %d\n", stringize(paste(number, 2)), paste(number, 2));
On a side note: why are you trying to do this? Surely there must be a better solution.
If you're compiling with GCC you can call it with gcc -E filename.c to see the expansion of macros.
EDIT:
You can also use the stringize preprocessor operator # that effectively puts double-quotes around the right-hand symbol.
#include <stdio.h>
#define T(...) #__VA_ARGS__
#define paste(f, b) _paste(f, b)
#define _paste(front, back) front##back
int main()
{
int n = 5;
printf("macro expands to: '%s'\n", T(paste(number, 2), paste(number, 2)));
printf("macro expands to: '%s'\n", T(paste(n, 2)));
return 0;
}
This code hopefully answers the question.
You need to expand the macro one more time to expand the paste in the stringize. In other words, for the paste macro inside the stringize macro to expand, the preprocessor has to pass over the file one more time. That's why you pass it through another macro defined later in the file.
I'm not 100% sure of ALL the rules of the preprocessor, but this seems to hold pretty well. For every macro you want to expand inside another macro, you need to do some magic to force the preprocessor to pass over the file again :) There exist different ways of achieving this to my knowledge, but this is one.
EDIT2:
Edited the code. I am getting this output, is this what you want?
morten#laptop:/tmp$ ./a.out
macro expands to: 'paste(number, 2), paste(number, 2)'
macro expands to: 'paste(n, 2)'

What does #define, EQ(a, b) ((a) == (b)) mean?

I have this been given C code where the heading statement includes the following:
#define, EQ(a, b) ((a) == (b))
What does it mean?
The comma is an error that will prevent the code from compiling: I'll assume that it's a typo.
Given:
#define EQ(a, b) ((a) == (b))
This defines a macro for the equality operator ==.
Using this macro later in the code, you can type, e.g.:
if (EQ(2+2, 4))
instead of:
if (2+2 == 4)
Not very useful, really.
It means nothing: this code is ill-formed. The token immediately following a #define must be an identifier, which , is not.
If the , were to be removed, this would define a function-like macro named EQ that takes two arguments.
Let's take it step by step
#define MAX 10
This will replace every instance of the word "MAX" by 10 in your code file. this is very much like defining a constant variable with one major difference. The interpretation of #define statement is done way before compilation. which helps for an example to use MAX as an array size. Which would have caused a compiler error in many cases if you have used a variable instead.
you can use cpp <filename.c> command in Linux terminal to see what will happen when a macro is executed.
for an example this code:
#define MAX 10
int numbers[MAX];
after preprocessing (i.e. interpretation of the preprocessor macros)
int numbers[10];
note that the #define statement will vanish once interpreted.
This takes us to another example
#define square(x) (x * x)
every instance of square(x) in our code will not only be replaced by (x * x) but also the value of x will be replaced. Which has an effect similar to function deceleration but again it is different
so
square(5) will be replaced by (5 * 5)
Finally our example
#define, EQ(a, b) ((a) == (b))
This will replace every instance of EQ(a, b) by ((a) == (b))
so for an example
EQ(4, 5) will be replaced by ((4) == (5))
Now what does "==" mean? it is the "check if equal" if 4 and 5 are equal the whole expression would evaluate as 1 (which obviously is not true) and thus this expression will end up to be evaluated as 0.
Which more or less like the effect of this function
int EQ(int a, int b)
{
return (a == b);
}
Which could be also written as
int EQ(int a, int b)
{
if (a ==b) return 1;
if (a !=b) return 0;
}
Note that with the macro we avoided two variable declarations and there is no function call really and it is in general quicker. This advantage will be obvious if you have a slower processor (or microprocessor).
Finally let me state the obvious
#define simple_macro 5
int some_integer_variable = 10;
.
.
.
some_integer_variable = simple_macro;
simple_macro = 12; /* illegal statement */
simple_macro++; /* illegal statement */
because after running the preprocessor this will be
int some_integer_variable = 10;
.
.
.
some_integer_variable = 5;
5 = 12;
5 ++;
Oh! I might have talked too much but let me leave you with this (obvious) code
#define MAX 10
int variable = MAX; /*this is a MAX variable */
char some_string[] = "the MAX value"; /* no replacement will happen here */
int variable_MAX; /* no replacement will happen here */
after running the preprocessor will be
int variable = 10;
char some_string[] = "the MAX value";
int variable_MAX;

How to concatenate two or more Integers using Macros?

If a=1, b=2, c=3... I would like to write a macro which concatenates them like this 123.
But when I try this:
#include<stdio.h>
#define cat(a,b,c) a##b##c
int main()
{
int a=1,b=2,c=3,d;
d=cat(1,2,3); //Works
d=cat(a,b,c); // Returns an error...How to make this work?
return 0;
}
You can't -- the preprocessor has no idea about variables and what values you're going to assign to them when the program runs at some arbitrary time after the preprocessor has finished executing.
hash-define macros are pre-compile time and are preprocessed before compilation. The preprocessor will not have access to variable values. d=cat(a,b,c) will get converted to d=abc by the preprocessor.
You would need to use itoa or something similar and concatenate the resulting strings and then atoi back.
Or just do some arithmetic to figure out the result.
Preprocessor stringifying can't work on variables, it has to take a literal and convert it to a string during processing; the preprocessor deosn't know what a, b, and c equals in your cat() call. You would need to write a macro that actually uses C++ to do the combining. For example:
#define cat(a, b, c, d) \
do { \
std::stringstream ss; \
ss << a << b << c; \
ss >> d; \
} while(0)
(the do/while(0) is a common hack to let you add a semi-colon after the cat call safely)
You won't be able to use a "return value" from this, but you can do:
int a = 1, b = 2, c = 3, d;
cat(a, b, c, d);
// d == 123 now
This might be a starting point:
#include <stdio.h>
#define cat(x,a,b,c) snprintf(x, sizeof(x), "%d%d%d", a, b, c)
main(int argc, char *argv[])
{
char s[20];
cat(s, 4,5,6);
printf("%s\n", s);
}
if it it isnt important that this is done at compile time, you can use something like this:
#include <math.h>
unsigned intcat(unsigned a, unsigned b, unsigned c)
{
unsigned dlogc = 1 + (unsigned)(log(c)/log(10));
unsigned dlogb = 1 + (unsigned)(log(b)/log(10));
return (unsigned)(c + pow(10,dlogc) * b + pow(10,dlogb+dlogc) * a);
}
i dont know if there is anything in the boost libraries to do such math at compile time using TMP.
It is possible for preprocessor defined integers.
The preprocessor needs a call to another function to expand.
You do it as follows:
#define I_BASE_CONCAT(x,y) x ## y
#define I_CONCAT(x,y) I_BASE_CONCAT(x,y)
There it is. Now if you call I_CONCAT it will expand it to x##y, but with the values of x and y.
The C preprocessor does just dummy text substitution at compile time.
What means text substitution? The preprocessor will output C code substituting the parameters of the macro with the passed values. It does not matter if you pass a variable or a constant number, you will just get dummy substitution (also called macro "expansion").
Let's go to see how the preprocessor will "expand" #define cat(a,b,c) a##b##c.
d=cat(1,2,3); expands to: d=123; and this is valid code because you have declared int d.
d=cat(a,b,c); expands to: d=abc; and this will not compile since there's no int abc variable.
What means compile time? It means that this text substitution is done on the source code, and the output disregards the content of the variables passed to the macro. In other words, it does not matters that you have initialized a, b, and c to 1, 2, and 3: the result will be just the concatenation (due to the ## "token-pasting" preprocessor operator) of the passed values. In your case the result is abc, which means nothing in your code.
You could also use this function to concatenate 3 integers
(the other intcat function above does not work when a 0 is the second or third digit. That is because the log of 0 is negative infinity and when you pass 0 it subtracts 1 from your total).
unsigned intcat(unsigned a, unsigned b, unsigned c)
{
uint8_t ax = a;
uint8_t bx = b;
uint8_t cx = c;
ax = (ax * 100);
bx = (bx * 10);
cx = (cx * 1);
return(ax + bx + cx);
}

Resources