Function overloading in C using GCC - compiler warnings

I am trying to implement function overloading in C and I am very close. I use C99, so the _Generic keyword introduced in C11 is not available to me. I developed some working code, but when I compile it, I get a couple of warnings.

Working example:

 #include <stdio.h> #define print(x) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int(x) , \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string(x), \ (void)0)) void print_int(int i) { printf("int: %d\n", i); } void print_string(char* s) { printf("char*: %s\n", s); } int main(int argc, char* argv[]) { print(1); print("this"); return 0; } 

Compilation generates the following warnings:

 gcc overload.c -o main overload.c: In function 'main': overload.c:19: warning: passing argument 1 of 'print_string' makes pointer from integer without a cast overload.c:20: warning: passing argument 1 of 'print_int' makes integer from pointer without a cast 

For more information on debugging, here is what the main function looks like after being executed by the preprocessor:

 int main(int argc, char* argv[]) { __builtin_choose_expr(__builtin_types_compatible_p(typeof(1), int ), print_int(1) , __builtin_choose_expr(__builtin_types_compatible_p(typeof(1), char[]), print_string(1), (void)0)); __builtin_choose_expr(__builtin_types_compatible_p(typeof("this"), int ), print_int("this") , __builtin_choose_expr(__builtin_types_compatible_p(typeof("this"), char[]), print_string("this"), (void)0)); return 0; } 

How can I get compilation warnings to go away and still have working code?

+8
c c-preprocessor c99 compiler-warnings function-overloading
source share
4 answers

In theory, this should work:

 #define print(x) \ (__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int , \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \ (void)0))(x)) 

It selects either print_int or print_string , then applies the selected function to x .

+7
source share

the GNU page in assemblies says that branches that are not selected can still generate syntax errors, but I don’t see how inconsistent types are syntax errors.

In any case, you can get rid of warnings when you move arguments from a function, regardless of type. So (in pseudo code to make it more readable) instead

 choose_type_of(x, int, print_int(x), choose_type_of(x, char[], print_string(x), (void) 0)) 

do

 choose_type_of(x, int, print_int, choose_type_of(x, char[], print_string, pass))(x) 

What user user2357112 suggested in a comment. I worked on a similar solution, but it was difficult for me to get the default part (above pass ). When I use (void) , which then needs to expand to (void)(x) , I get an error message with an inconsistent bracket.

The solution below creates a default print function that does not use its arguments. This may probably be a non-existent function, so there are problems with the binding or something else that creates an error.

 #include <stdio.h> #define print(x) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), \ int), print_int, \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), \ const char[]), print_string, \ print_any))(x) void print_int(int i) { printf("int: %d\n", i); } void print_string(const char *s) { printf("char[]: %s\n", s); } void print_any() { printf("unknown\n"); } int main(void) { int n = 9; const char str[] = "hello"; print(n); print(str); print(1); print("this"); print(3.2); return 0; } 
+2
source share

Here is an example with several methods that provide function overloading.

One poster mentioned this.

On the GNU page, the lines indicate that unselected branches may still generate syntax errors, but I do not see how inconsistent types are syntax errors.

The syntax errors to which they refer are, I believe, the compiler warnings you receive, because after preprocessing, the compiler can see that the argument types for some functions, even if they can never be called, are incorrect. The solution (which I find pretty neat) is to find a way to hide types from the compiler. The obvious way is varargs, the less obvious way is the current answer to the OP question.

Cautions apply, i.e. not all solutions are type safe, and this is completely specific to GNU ...

 #include <stdarg.h> #include <stdlib.h> #include <stdio.h> #define print(x) \ (__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int , \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \ (void)0))(x)) #define print1(x) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int1(1,x) , \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string1(1,x), \ (void)0)) #define print2(x) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), printer(1,x), \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), printer(2,x), \ (void)0)) #define TYPE_ID(x) __builtin_types_compatible_p(typeof(x), int ) * 1 \ + __builtin_types_compatible_p(typeof(x), char[]) * 2 #define print3(x) printer(TYPE_ID(x), x) #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1] #define print4(x) \ STATIC_ASSERT(TYPE_ID(x), __LINE__); \ printer(TYPE_ID(x), x) void printer(int i, ...) { va_list v; va_start(v, i); switch(i) { case 1:{ int arg = va_arg(v, int); printf("int: %d\n", arg); va_end(v); break; } case 2:{ char * arg = va_arg(v, char*); printf("char*: %s\n", arg); va_end(v); break; } default: { fprintf(stderr, "Unknown type, abort\n"); abort(); } } } void print_int(int i) { printf("int: %d\n", i); } void print_string(char* s) { printf("char*: %s\n", s); } void print_int1(int i, ...) { va_list v; va_start(v, i); int arg = va_arg(v, int); printf("int: %d\n", arg); va_end(v); } void print_string1(int i, ...) { va_list v; va_start(v, i); char * arg = va_arg(v, char*); printf("char*: %s\n", arg); va_end(v); } int main(int argc, char* argv[]) { int var = 1729; double var1 = 1729; //Type safe //print(var1);//Comple time error print(var); print("print"); /* Following are not Type Safe */ print1(var1);// BAD... Does nothing. print1(var); print1("print1"); print2(var1);// BAD... Does nothing. print2(var); print2("print2"); //print3(var1);//Evil... Runtime error print3(var); print3("print3"); //Type Safe //print4(var1);//Comple time error print4(var); print4("print4"); return 0; } 

The source is in github ...

https://github.com/harryjackson/doc/blob/master/c/overload_c_functions.c

A switch method with multiple arguments can be found here ...

http://locklessinc.com/articles/overloading/

Whole

+1
source share

You can suppress the warning by doing some type casting in the #define section, but I feel that this is probably not the best or even a good solution at all ...

Change the function calls in the #define section to the following:

 print_string((char*)x) print_int((int)x) 

I really hope that someone comes up with a better solution, because it is simply wrong ...

0
source share

All Articles