Function overloading in C with _Generic when __VA_ARG__ can be empty - c

I am looking to use the _Generic preprocessor directive to achieve function overloading. I learned to use it from this wonderfully detailed answer.
However, it doesn't seem to cover this case:
#include <stdio.h>
void foo_one(int);
void foo_two(int, float*);
#define FIRST_VARG(_A, ...) _A
#define foo(_X, ...) _Generic( (FIRST_VARG(__VA_ARGS__,)), \
float* : foo_two, \
default : foo_one) (_X, __VA_ARGS__)
void foo_one(int A)
{
printf("FOO ONE: %d\n", A);
}
void foo_two(int A, float* B)
{
printf("FOO TWO: %d, %f", A, *B);
}
void main()
{
float x = 3.14;
float* y = &x;
foo(1); // This statement pops an error
foo(2, y);
}
Here, you can see that the first argument to both functions is an integer. However, the second argument of the second function is a float*. Visual Studio complains about the calling foo(1), but not when calling foo(2, y). The error is
error C2059: syntax error: ')'
I know Visual Studio can support _Generic with a small trick. So, I feel like there is something I am doing wrong. There is a comment in the answer where I learned about _Generic that suggests using (SECOND(0, ##__VA_ARGS__, 0), etc. But I don't understand it.
Can someone walk me through how I could achieve my intended result?

There are two issues. First is selecting the second argument of foo for generic selection in the case when there is no second argument.
Other is #define foo(_X, ...) which will not work for foo(1) because the function macro expect two or more arguments. It often works but it a compiler specific extensions. Compiling in pedantic mode will raise a warning. See https://godbolt.org/z/z7czvGvbc
A related issue is expanding to (_X, __VA_ARGS__)which will not work for foo(1) where ... maps to nothing.
The both issues can be addressed with placing a dummy type (NoArg) at the end of the list prior to extracting the second argument. It will both extend the list and add a value that can be used by _Generic to correctly dispatch the function expression.
#include <stdio.h>
void foo_one(int);
void foo_two(int, float*);
typedef struct { int _; } NoArg;
// use compound literal to form a dummy value for _Generic, only its type matters
#define NO_ARG ((const NoArg){0})
#define foo_(args, a, b, ...) \
_Generic((b) \
,NoArg: foo_one \
,default: foo_two \
) args
// pass copy of args as the first argument
// add NO_ARG value, only its type matters
// add dummy `~` argument to ensure that `...` in `foo_` catches something
#define foo(...) foo_((__VA_ARGS__), __VA_ARGS__, NO_ARG, ~)
void foo_one(int A)
{
printf("FOO ONE: %d\n", A);
}
void foo_two(int A, float* B)
{
printf("FOO TWO: %d, %f\n", A, B ? *B : 42.0f);
}
#define TEST 123
int main(void)
{
float x = 3.14;
float* y = &x;
foo(1); // This statement pops an error
foo(2, y);
foo(TEST, NULL);
return 0;
}
The last issue is addressed by passing a tuple with original arguments as extra argument to foo_ macro, this argument is later passed to the call operator of expression selected by _Generic.
This solution works with all major C17 compilers (gcc, clang, icc, msvc).

Related

Macros used as simple functions

Hi, I tried to define something comparable to a little function, even though it doesn't output any error the result is: 0.00000000
#include <stdio.h>
#define LOGIC(X,Y){\
if(X>Y)\
printf("%lf",X);\
else\
printf("%lf",Y);\
}
int main(){
LOGIC(4,3);
return 0;
}
Why is so and how to make it work?
First, you should have a very good reason to choose a macro like function over an actual function. If you had used a function, you would be able to specify that the function parameters should be double more naturally.
void logic (double x, double y) {
if (x > y) {
printf("%lf\n", x);
} else {
printf("%lf\n", y);
}
}
Since you are using a macro, there is no type specified for the arguments. So, if you pass in an int argument to the macro, that is how it is treated in the expansion. Undefined behavior results when printf is told to expect a double parameter when an int was passed in instead.
One way to fix the macro is to assign the parameters to local variables with the appropriate type, which better emulates what an actual function would do.
#define LOGIC(X,Y) do {\
double XX = (X); \
double YY = (Y); \
if(XX>YY)\
printf("%lf",XX);\
else\
printf("%lf",YY);\
} while (0)

Using C11's _Generic to emulate default value of argument [duplicate]

I have two functions foo1(a,b) & foo2(a,b,c) and a macro
#define add(a,b) foo(a,b)
I need to re-define macro to accomplish,
1.if add() is called with 2 parameters, then call foo1
if add() is called with 3 parameters then call foo2
Im new to the option VA_ARGS. How can I do that
If you just want to distinguish between two functions, the following works:
#define ADD(_1, _2, _3, X, ...) X
#define add(...) ADD(__VA_ARGS__, add3, add2, 0)(__VA_ARGS__)
The auxiliary macro ADD always picks the fourth argument:
add(a, b) --> ADD(a, b, add3, add2, 0) --> add2
add(a, b, c) --> ADD(a, b, c, add3, add2, 0) --> add3
The drawback is that you get quite cryptic error messages when you don't supply two or three arguments to the function.
The advantage over variadic functions is that you get type safety. For example if your functions operate on doubles, you can still say add(1, 2) and the integer arguments will be converted to doubles. And variadic functions require some additional information on the number of actual arguments, so that's not a feasible solution here, unless you specify the number of summands in the function.
Addendum: I've changed the add macro so that it doesn't pass an empty variadic list to ADD. Some compilers allow empty lists, but it isn't standard C.
That usual trick for counting arguments may be adapted for this:
#define ADD_EXPAND(...) \
ADD_EXPAND_(__VA_ARGS__, EXPAND_ADD_FUNCS())
#define ADD_EXPAND_(...) \
EXPAND_ADD_SEL_FUNC(__VA_ARGS__)
#define EXPAND_ADD_SEL_FUNC(first_, second_, third_, func, ...) func
#define EXPAND_ADD_FUNCS() foo2, foo, dummy
#define add(...) ADD_EXPAND(__VA_ARGS__)(__VA_ARGS__)
Once you plow through the boiler plate, it basically just involves placing all the arguments in a line, with the function tokens after them, and seeing which function stands out. That's what EXPAND_ADD_SEL_FUNC does.
You can see it live on coliru.
But I'll reiterate what we told you in comments. This is likely to be a sub-par solution to a proper function. I haven't tested it thoroughly, so breakage is easily possible. Use at your own risk.
If you must use variadic macros, then here is a trick.
#define add(...) _Generic ( &(int[]){__VA_ARGS__}, \
int(*)[2]: add2, \
int(*)[3]: add3) (__VA_ARGS__)
Have the macro create a compound literal array. The size of this array will depend on the number of arguments.
Grab the address of the compound literal, to get an array pointer type.
Let _Generic check which type you got, then call the proper function based on that.
This is 100% standard C and also type safe.
Demo:
#include <stdio.h>
#define add(...) _Generic ( &(int[]){__VA_ARGS__}, \
int(*)[2]: add2, \
int(*)[3]: add3) (__VA_ARGS__)
int add2 (int a, int b);
int add3 (int a, int b, int c);
int main (void)
{
printf("%d\n", add(1, 2));
printf("%d\n", add(1, 2, 3));
//printf("%d\n", add(1, 2, 3, 4)); Compiler error for this.
}
int add2 (int a, int b)
{
return a + b;
}
int add3 (int a, int b, int c)
{
return a + b + c;
}

Use of pasting operator `##` with types in C

Is it possible to define a macro for the C preprocessor which takes an array as argument and expands to <type of array elements>_string? For example if x in an array of integers the macro invoked with argument x should expand to int_string.
I tried with
#define TypePaste(array) typeof(array[0])##_string
but it expands to )_string.
Even using multiple levels of indirection for the ## operand the macro doesn't expand correctly.
That's not possible. At the translation phase (the preprocessing phase) where macros are expanded and tokens are concatenated, the compiler (at this point, the preprocessor) does not yet have the notion of a type and thus cannot possibly generate types.
It is not all that clear what problem you are trying to solve, but given your comment:
the macro should expand to the name of an existing function. I'd like to define a function <type>_string for every existing type and then use the macro to select the right function according to the type of the array given.
Then you could use the C11 _Generic keyword:
#include <stdio.h>
void int_string (size_t size, int array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
void float_string (size_t size, float array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
#define TypePaste(array) \
_Generic( array, \
int: int_string, \
float: float_string ) \
(sizeof(array)/sizeof(*array), array) // function parameters
int main()
{
int i_arr[5];
float f_arr[3];
TypePaste(i_arr);
TypePaste(f_arr);
}
Output:
I am int_string, do stuff here.
I am float_string, do stuff here.
Note: this assumes that the passed parameter is a local/file scope allocated array. If passing a pointer, there's no type safety and the program will fail.
C11's _Generic type selection is the "proper" way to do what you want. There are other, platform dependent solutions, tough.
If you are using gcc – you don't say so eplicitly, but you use gcc's extension typeof already – you can use gcc's statement expresions and nested functions to create a comparison function for qsort on the spot:
double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2};
qsort(a, 5, sizeof(*a), ({
int cmp(const void *p, const void *q) {
const typeof(a[0]) *pp = p;
const typeof(a[0]) *qq = q;
return (*pp < *qq) ? -1 : (*pp > *qq);
}
cmp;
}));
This creates a function and returns its address. (The last statement of a compound expression is its value. The scope of the local variables is the statement expression, but a nested function is not created on the stack so its safe to return a pointer to that function.)
For primitive types, where you want to sort according to the comparison operators < and >, you can turn that into a macro:
#define COMPARE(ARRAY)({ \
int cmp(const void *p, const void *q) { \
const typeof(ARRAY[0]) *pp = p; \
const typeof(ARRAY[0]) *qq = q; \
return (*pp < *qq) ? -1 : (*pp > *qq); \
} \
cmp; \
})
qsort(a, 5, sizeof(*a), COMPARE(a));
or even:
#define SORT(ARRAY, N) \
qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY))
SORT(a, 5);
That's not Standard C, so if you need compatibility between platforms, this is out of the question.

(C99)Expand a macro in a different macro

I have a function in my program that takes 3 arguments. Some times in the code there is a macro defining 2 of these parameters.
So this:
void func(int x, int y, int z){...}
Can be invoked like this:
#define PAR 10,20
int z = 3;
func(PAR, z);
Now, I need to change my code so that the function is called like a macro for another function.
#define func(X,Y,Z) func2(X,Y,Z,#Z)
This works fine if X and Y are really passed as variables. Is there any way to make it work also with the macro PAR?
I'm using GCC 4.6
You can do this with an extra level of indirection, (ab)using variadic
macros:
#include <stdio.h>
#define PAR 2,3
#define F(...) G(__VA_ARGS__)
#define G(a,b,c) H(a,b,c)
void H(int a, int b, int c) {
printf("%d %d %d\n", a , b, c);
}
int main() {
F(PAR, 42);
return 0;
}
There is probably a better solution for the underlying problem.
No, I don't believe so. When you define
#define func(X,Y,Z) func2(X,Y,Z,#Z)
You're defining a function-like macro. func(X,Y,Z) actually takes three arguments - and it has to take three arguments. Remember, the preprocessor and not the compiler is interpreting func(PAR, Z).
I've struggled to find any documentation, but it makes sense that the first thing the preprocessor will do (considering that func() is the outer element) is to check to see if the arguments to func() are valid. Then it will place the arguments into func2() and will then expand any macros that were passed as arguments. The code I placed below seems to back up this claim.
Following this logic, the preprocessor will see that func(PAR, Z) isn't a valid call because an argument is missing, which will then throw the error
13:12: error: macro "func" requires 3 arguments, but only 2 given
func(X, Y, Z) will work so long as X and Y are valid macros or variables.
Code (this will give you warnings because there is no function declaration, but the output will be "3 14 3" as expected):
#include <stdio.h>
#include <stdlib.h>
#define PAR 10,20
#define MAR 3
#define WAR 14
#define func(X,Y,Z) print(X, Y, Z)
int Z = 3;
int main(void){
func(MAR,WAR,Z);
return 0;
}
void print(int x, int y, int c){
printf("%d %d %d\n", x, y, c);
}
Out of curiosity, why are you doing this (I don't have enough reputation to comment yet FYI).

Passing variable type as function parameter

Is it possible to pass variable type as part of a function parameter, e.g.:
void foo(varType type)
{
// Cast to global static
unsigned char bar;
bar = ((type *)(&static_array))->member;
}
I remember it has something to do with GCC's typeof and using macros?
You could make an enum for all different types possible, and use a switch to make the dereferencing:
typedef enum {
CHAR,
INT,
FLOAT,
DOUBLE
} TYPE;
void foo(TYPE t, void* x){
switch(t){
case CHAR:
(char*)x;
break;
case INT:
(int*)x;
break;
...
}
}
You can't do that for a function, because then it needs to know the types of the arguments (and any other symbols the function uses) to generate working machine code. You could try a macro like:
#define foo(type_t) ({ \
unsigned char bar; \
bar = ((type_t*)(&static_array))->member; \
... \
})
Eh, of course you can. Just use a macro like so:
#include <stdio.h>
#define swap(type, foo, bar) ({type tmp; tmp=foo; foo=bar; bar=tmp;})
int main() {
int a=3, b=0;
swap(int, a, b); // 👈 check it out!
printf("a=%d, b=%d \n", a, b); // a=0, b=3
return 0;
}
I don't see how you could do this in the general case, given that C is a statically typed language.
The compiler needs to know at compile time what the type of type * is in order to be able to generate the reference to ->member.

Resources