Passing macro arguments to macro function - c

How do I pass macro arguments along with another integer variable to a macro function?
#define SUM(X, Y, Z) X + Y + Z
#define FOO 1, 2
void print(int a, int b)
{
printf("Sum: %d", a + b);
}
int main(void)
{
// Normal function works as expected
print(FOO);
// Macro function not working
int a = 3;
printf("\nMacro Sum: %d", SUM(FOO, a));
return 0;
}
I expect the output to be:
Sum: 3
Macro Sum: 6
However, I get the following error:
main.c:18:41: error: macro "SUM" requires 3 arguments, but only 2 given
printf("\nMacro Sum: %d", SUM(FOO, a));

Macro arguments are not expanded when the macro call is parsed. After the macro call is parsed, each use of a macro parameter in the macro definition text is replaced with the macro-expanded argument, except for macro parameters used with the # or ## operations (stringify and token paste), which are replaced with the unexpanded text of the macro argument. Then the # and ## operations are performed, and then the entire macro body is scanned one more time.
The consequence is that SUM(FOO, a) is parsed aa having two arguments. Since the macro requires three, thatvwon't compile.
You can work around this, to some extent, by using one extra level of macro expansion:
#define CALL(macro, ...) macro(__VA_ARGS__)
printf("\nMacro Sum: %d", CALL(SUM, FOO, a));
Now the use of the __VA_ARGS__ parameter (which happens to be a varargs parameter, although that makes absolutely no difference to the expansion order) will be expanded before the replacement text is rescanned, so FOO will be invoked with three arguments.
By the way, outputting a newline character at the beginning of an output line is a bad habit which will get you into trouble someday. Output lines should have a newline at the end of the line:
printf("Macro Sum: %d\n", CALL(SUM, FOO, a));
There is nothing wrong with also writing a blank line beforehand by putting a newline at the beginning as well, but regardless, you should almost always terminate outpur lines with the \n. Otherwise:
The line might not be written immediately. Line-buffered output is not actually sent to the output device/file until a newline is sent.
If the program is a console app and it terminates without properly closing stdout, you will find yourself typing the next shell command at rhe end if the last output line. This tends to confuse line-editing input libraries like readline.

Single macro argument would work:
#define SUM(X, Y, Z) X + Y + Z
#define FOO1 (1)
#define FOO2 (2)
void print(int a, int b)
{
printf("Sum: %d", a + b);
}
int main(void)
{
// Normal function works as expected
print(FOO1,FOO2);
int a = 3;
printf("\nMacro Sum: %d", SUM(FOO1, FOO2, a));
return 0;
}
Output:
Sum: 3
Macro Sum: 6

Related

Can we use recursive macro to create varadic max/min?

Need max/min with unknown number of arguments, like :
#define MAX_N(first, second, remain...) MAX_N(((first)>(second)?(first):(second)), ##remain)
In my opinion, this will not keep expanding infinitely and should be accepted by compiler?
Unfortunately, I have to use pure C rather than C++.
C 2018 6.10.3.4 2 says, about rescanning the result of macro replacement for further macros:
If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced…
Therefore, recursive macros are not possible, not even just for two levels, let alone indefinitely many.
It is possible to cause macros to be expanded multiple times by using other macros to expand them. As a simple example, after #define X Y Y, X will be replaced by two occurrences of Y, each of which, if it is a defined macro, will be replaced—but separately, not recursively. This can be exploited to create macros that cause sone finitely limited number of expansions, but indefinitely many expansions are not possible.
Why do you need a recursive macro? you can write a variadic min/max function like this:
#include <stdio.h>
#include <stdarg.h>
// credit for NUMARGS: https://stackoverflow.com/a/2124433/2889478
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define MAX(...) (max_variadic(NUMARGS(__VA_ARGS__), __VA_ARGS__))
int max_variadic(int narg, ...)
{
va_list args;
int pos = 0, max_val = 0;
va_start(args, narg);
while (narg--) {
int i = va_arg(args, int);
max_val = !pos ? i : i > max_val ? i : max_val;
pos++;
}
va_end(args);
return max_val;
}
int main(void)
{
int mx = MAX(4, 6, -1, 9, 2);
printf("%d", mx);
}

Argument counting in macro

I'm trying to understand the argument counting in C preprocessing macro and the idea in this answer. We have the following macro (I changed the number of arguments for simplicity):
#define HAS_ARGS(...) HAS_ARGS_(__VA_ARGS__, 1, 1, 0,)
#define HAS_ARGS_(a, b, c, N, ...) N
As far as I understand the purpose of this macro is to check if the given varargs empty. So on empty varargs the macro invokation is replaced with 0 which seems fine. But with a single argument it also turns into 0 which I seems strange.
HAS_ARGS(); //0
HAS_ARGS(123); //also 0
HAS_ARGS(1, 2); //1
LIVE DEMO
I think I understand the reason. In case of empty varargs a is replaced with empty preprocessing token, in case of a single argument vararg a is replaced with the argument yielding the same result.
Is there a way to get 0 returned in case varargs are empty, 1 in case argument number is from 1 to the defined in HAS_ARGS_ macro invokation without using comma-swallowing or other non-conforming tricks. I mean
SOME_MACRO_F() //0
SOME_MACRO_F(234) //1
SOME_MACRO_F(123, 132) //1
//etc
You cannot pass zero arguments to HAS_ARGS(...). ISO C (and C++, at least for the next two years) requires that an ellipsis corresponds to at least one additional argument after the last named one.
If there are no named ones, then the macro needs to be passed at least one argument. In the case of HAS_ARGS() the extra argument is simply an empty token sequence. Zero arguments is simply not possible.
This is exactly the use case in the answer. The target macro expects at least one argument. So we can use a wrapper accepting only an ellipsis for "overload resolution". A better name probably would have been HAS_MORE_THAN_1_ARGS. Because that's what the predicate is meant to tell you. Alas, I favored brevity on that answer.
It seems difficult to compute that at compile-time, but you can do it at run-time by stringifying the arguments and testing if the string is empty.
Tested with gcc:
#include <stdio.h>
#define HAS_ARGS(...) (#__VA_ARGS__[0] != '\0')
int main()
{
printf("%d %d %d %d\n",HAS_ARGS(),HAS_ARGS(10),HAS_ARGS(20,"foo"),HAS_ARGS(10,20));
return 0;
}
this prints:
0 1 1 1
behind the scenes, here's what the pre-processor outputs:
int main()
{
printf("%d %d %d %d\n",(("")[0] != '\0'),(("10")[0] != '\0'),(("20,\"foo\"")[
0] != '\0'),(("10,20")[0] != '\0'));
return 0;
}

Ununderstandable function-like macro in C

i have this c macro code :
#define d(x, y, z) ( \
x += z, \
y += x, \
x += y \
)
I have several questions :
Does this macro function return something ? (e.g. return x, y, or z)
or is it just add the parameter variable with itself ? (which is
useless, i think).
What does the \ means ?
Why does the original coder use comma-operator after each operation ? Why not just use ; instead of , ?
Any help would be appreciated
Does this macro function return something ? (e.g. return x, y, or z) or is it just add the parameter variable with itself ? (which is useless, i think).
It modifies the value of the variables. The "return" value is the final value of x.
What does the \ means ?
When placed last on a line, it negates the newline so that the macro definition can span more than one line.
Why does the original coder use comma-operator after each operation? Why not just use ; instead of `, ?
Macros replace text. Consider the following code:
int x=1, y=2, z=3, f;
f = 3 * (d(x,y,z));
If the macro uses comma, the code becomes:
int x=1, y=2, z=3, f;
f = 3 * (x+=z, y+=x, x+=y); // Evaluates to 3 * (the final value of x)
If the macro uses semicolon, the code becomes:
int x=1, y=2, z=3, f;
f = 3 * (x+=z; y+=x; x+=y); // Syntax error!!!
1) The macro does not return anything itself. It is just a dumb piece of code substituted literally by the preprocessor wherever it encounters it. It can be any kind of text.
2) \ is used for letting the preprocessor know that the current macro also expands over the next line. (multi-line macro)
3) I cannot make any assumption about the original coder's intentions. However by using the comma operator in there the whole macro becomes a C language expression. For example running something like this works (it wouldn't if semicolons were in there):
int a = 0;
int x = 1;
int y = 2;
int z = 3;
a = d(x, y, z);
printf("a = %d\n", a);
printf("x = %d\n", x);
printf("y = %d\n", y);
printf("z = %d\n", z);
and prints:
a = 10
x = 10
y = 6
z = 3
First and foremost #define is a Preprocessor Directive, which means when the source code/c code is complied the #define replaces LHS with RHS - meaning whereever the d(x,y,z) is used will be replaced with the equation given
for example the below c code will print - modified a = 9, b=8, c=9
#define d(x,y,z) \
x+=1, \
y+=2, \
z+=3
#include <stdio.h>
int main()
{
unsigned int a,b,c;
a=5;
b=6;
c=7;
printf("modified a = %d, b=%d, c=%d \n",d(a,b,c));
}
basically what happened here is d(a,b,c) - is replaced with a+=1,b+=2,c+=3
The meaning of \ is that the pre-processor directive continues in the next line.
As for as the comma-operator is concerned we need to look at source code to see where exactly it is used. as you can see in the above code the comma operator actually separates all the three variables and is able to print properly - if in case i replace comma with any other operator we will get compilation error.
Hope this answers your questions :)
Regards
Hari

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

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