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

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

Related

mixture of string and number in macro

I want to use this macro to put (if 'i' is greater than zero) the symbol '^' and the number I pass (i) to the macro
#define ESP(i) ((i>0) ? ("^"(i)) : "")
I want to call it in this way
printf("%+d%s", n1, ESP(i));
where 'i' is the index of a cycle, but the compilation reports me errors;
how can I modify the code to be right?
Somewhat dirty but should work:
#include <stdio.h>
#define DYNFORMAT(n, i) (i>0) ?"%+d%s%d\n" :"%+d%s%s\n", n, (i>0) ?"^" :"", (i>0) ?i :""
int main(void)
{
int i = 0;
printf(DYNFORMAT(42, i));
i = 1;
printf(DYNFORMAT(42, i));
}
This should print:
+42
+42^1
Disclaimer: I am not sure whether this conforms to the Standard and how to get rid of the warning(s) it gives during compilation.
The clean approach would be to use two calls to printf().
This can be implemented as a macro or a function.
As I love the pre-processor, the macro version here:
#define PRINT_ESP(n, i) \
do { \
if (i = 0) \
printf("%+d", n); \
else \
printf("%+d^%d", n, i); \
} while (0);
Macros operate at compile time, not at run time. They can perform a variety of text-mangling tricks, but they do not evaluate anything. (They can certainly, however, expand to code that evaluates something.) Putting the formatted value of variable i into a string involves evaluating i; no macro can do this.
You could instead expand the scope of the macro to include the whole printf() call:
#define PRINT_ESP(n1, i) do { \
printf(((i > 0) ? "%+d^%d" : "%+d"), n1, i); \
} while (0)
Alternatively, you could use a macro to express just the format selection incorporated into the above macro definition, or you could just put the full printf() call above directly into your code.
All of these variations are based on the fact that arguments in excess of those required by the given format are evaluated prior to the call, but ignored by printf() itself.
You don't need the (i) after the "^". Change your macro to this and it should work #define ESP(i) ((i>0) ? ("^") : ("")). Then in your printf statement if you want to print the value of i after the "^" then have something like this printf("%s%d", ESP(i), i); As far as I know I don't think you can format a string to include an integer inside a macro since that would require calling other functions, so you have to bring the i into the string inside your printf.

Renaming a macro in C

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

Are there restrictions/problems with naming macros in C?

I want to have functions which can have optional arguments. Of course this cannot be done with C, but it is possible with some macro magic:
#define _macroWith1Arg(_0, _1, macroName, ...) _ ## macroName
#define _macroWith2Args(_0, _1, _2, macroName, ...) _ ## macroName
#define _macroWith3Args(_0, _1, _2, _3, macroName, ...) _ ## macroName
#define macroWith1Arg(macroName, ...) _macroWith1Arg(_0, __VA_ARGS__, macroName ## _1, macroName ## _0)(__VA_ARGS__)
#define macroWith2Args(macroName, ...) _macroWith2Args(_0, __VA_ARGS__, macroName ## _2, macroName ## _1, macroName ## _0)(__VA_ARGS__)
#define macroWith3Args(macroName, ...) _macroWith3Args(_0, __VA_ARGS__, macroName ## _3, macroName ## _2, macroName ## _1, macroName ## _0)(__VA_ARGS__)
#define _sum_1(_1) (_1)
#define _sum_2(_1, _2) (_1) + (_2)
#define sum(...) macroWith2Args(sum, __VA_ARGS__)
fprintf(stderr, "%d ", sum(1)); // Prints 1
fprintf(stderr, "%d ", sum(1, 2)); // Prints 3
I like the way it looks: it looks like a normal function with optional arguments. But the drawback of this is you can't have a function pointer to a macro like sum. So I heard you should capitalize the name to mark it explicit as a macro (like "SUM") to avoid confusion.
Now I my question is: is this naming convention really necessary, I mean standard C does it with errno for example (at least on my platform)? I think most IDEs can identify macros and highlight them as such. I would really like to hear your opinion on this.
EDIT:
I found a way to achieve that you can take a function pointer:
int my_sum(int, int);
#define _sum_1(_1) my_sum(_1, 0)
#define _sum_2(_1, _2) my_sum(_1, _2)
#define sum(...) macroWith2Args(sum, __VA_ARGS__)
int (*sum)(int, int) = my_sum;
// Use it as a "function":
fprintf(stderr, "%d ", sum(1, 2)); // Prints 3
// Take a function pointer:
int (*sumptr)(int, int) = sum;
fprintf(stderr, "%d ", sumptr(1, 0)); // Prints 1
In C (the preprocessor is part of it) you can do even more than you are suggesting in your edit: macros and functions can have the same name. Whereas this is rarely done in application code, the C library itself can have that. Here standard functions can be implemeted as macros, but a symbol with the same name must also be provided.
So the standard itself doesn't stick to the rule that macro names should be all caps.
I think that if you are careful in your implementation such that
calling the macro with a full set of parameters just is the identity in the preprocessor phase
a valid function declaration is provided with the same name
then there should be no problem in using a lowercase identifier.
By that you ensure that
repeating the prototype for your function is still a valid operation
taking a function pointer can be done without problems
and in all your implementation is behaving as if your macro where a function.
BTW, the code that you posted is not standard conforming. Indentifiers starting with an underscore are reserved in file scope. This is not a convention but imperative.
Naming conventions generally aren't necessary. They exist to communicate information to other programmers (including yourself a few weeks/months in the future). When another programmer sees
sum(a, b, c, d);
They will immediately think that it's a normal function that takes 4 parameters. However, if they see
SUM(a, b, c, d);
Then they will know it's a macro (assuming they are familiar with C naming conventions). After all, you're not always going to be viewing files in an IDE that knows about what macros and functions you've defined. People will see your code in diff tools and in text editors. They will generally expect macros to be in all caps and symbols that aren't in all caps to be things other than macros.
convention works less in C. since C has fewer tools and compiler does less work, programmers have to be flexible to achieve some purpose. say the convention of macros is uppercase + underscore, but if you want to make people think some macros are functions, it's better for you to not follow this convention. in fact, some libraries fake a field in struct by not following this convention.
you mentioned errno. it's a good example. it's essentially a macro(glibc), returning a left value, so you can write errno = 0;. so in this way, library provider made you think errno was a global variable(this used to be what i thought it was too.), which is not. C programmers tend to be flexible and play some reasonable tricks. it's not the same as Java or C# this kind of enterprise oriented languages, which require programmers to strictly follow conventions.
// notice that the handling of a variable argument list
// is simple, built into C, and does not require a bunch of
// home grown macros.
// this function will take the number of values to average
// followed by all of the numbers to average
double average ( int num, ... )
{
va_list arguments; // A place to store the list of arguments
double sum = 0;
va_start ( arguments, num ); // Initializing arguments to store all values after num
for ( int x = 0; x < num; x++ ) // Loop until all numbers are added
{
sum += va_arg ( arguments, double ); // Adds the next value in argument list to sum.
}
va_end ( arguments ); // Cleans up the list
return sum / num; // Returns the average
}

Macro expansion for macros with arguments vs. variables with the same name

Consider the following C program (ignore the double side-effect issue):
#define max(a, b) (a>b?a:b)
int main(void){
int max = max(5,6);
return max;
}
The GCC preprocessor turns this into:
int main(void){
int max = (5>6?5:6);
return max;
}
Which is quite nice, since you don't have to worry about unintentional collisions between max and max(). The GCC manual says:
A function-like macro is only expanded if its name appears with a pair of parentheses after it. If you write just the name, it is left alone
Is this standardized or just something done by convention?
Yes, the behavior here is well-defined.
Your macro max is a function-like macro (i.e., when you define it, its name is followed immediately by a left parenthesis and it takes arguments).
A use of max later in your code is only an invocation of that macro if the use of max is followed by a left parenthesis. So, these would not invoke the max macro:
int max;
max = 42;
But these would all invoke the max macro:
max(1, 2)
max (1, 2)
max
(
1, 2
)
max()
(Note that the last line is ill-formed because the number of arguments does not match the number of parameters. This is still a macro invocation, though, and would cause a compilation error.)
This behavior is mandated by the C langauge standard. C99 §6.10.3/10 states that after a function-like macro has been defined,
Each subsequent instance of the function-like macro name followed by a ( as the next preprocessing token introduces the sequence of preprocessing tokens that is replaced by the replacement list in the definition (an invocation of the macro).

use of ## and # operator to concatenate the strings in a macro in C

I am having a code which requires to concatenate strings as shown below:
#define CMD(A,B) CMD_##A_PROMPT##B
void main()
{
int a = 10, b = 5;
printf("%s\n", CMD(a, b));
}
the desired output is: CMD10_PROMPT5
Can this be achieved by any means?
I don't think that this can be done, because the macro you're looking for is a compile-time "stringification", an the parameters receive their values at run-time.
If you're looking for run-time "stringification", use sprintf and the like.
You can do it by replacing int a = 10, b = 5; with:
#define a 10
#define b 5
Otherwise it's not possible. C translation occurs in a series of phases defined in the standard, and preprocessing phase occurs before any object definitions are parsed. As far as the preprocessor is concerned, int a = 10 does not establish any relationship between the token a and the token 10.
If all you're after is the output, do it like this:
#define CMD_PATTERN "CMD_%d_PROMPT%d"
int main() {
int a = 10, b = 5;
printf(CMD_PATTERN "\n", a, b);
}
There's unfortunate requirement that the arguments are supplied in the same order that they appear in the pattern - this makes it difficult to change the order in future. For that reason, it might be better to define a formatting function rather than just a pattern.

Resources