Función de sobrecarga en C usando GCC – advertencias del comstackdor

Estoy intentando implementar la sobrecarga de funciones en C , y estoy muy cerca. Estoy utilizando C99, por lo que la palabra clave _Generic introducida en C11 no está disponible para mí. He desarrollado un código de trabajo, pero cuando lo compilo recibo un par de advertencias.

Ejemplo de trabajo:

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

La comstackción crea las siguientes advertencias:

 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 

Para un poco más de información de depuración, aquí está la función principal después de que el preprocesador haga su trabajo:

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

¿Cómo puedo hacer que desaparezcan las advertencias de comstackción y aún tenga un código de trabajo?

En teoría, esto debería funcionar:

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

Elige print_int o print_string , luego aplica la función elegida a x .

La página de GNU en los complementos dice que las twigs no elegidas aún pueden generar errores de syntax, pero no veo cómo los tipos no coincidentes son errores de syntax.

De todos modos, puede deshacerse de las advertencias cuando mueva los argumentos a la función fuera de la elección dependiente del tipo. Entonces (en pseudocódigo para hacerlo más legible), en lugar de

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

hacer

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

Eso es lo que user2357112 sugirió en un comentario. Estaba trabajando en una solución similar, pero me costó mucho conseguir que funcionara la parte predeterminada (el pass anterior). Cuando uso (void) , que luego debería expandirse a (void)(x) , aparece un error sobre un paréntesis no coincidente.

La solución a continuación crea una función de impresión predeterminada que no utiliza sus argumentos. Probablemente podría ser una función inexistente, por lo que hay problemas al vincular o algo más que produce un error.

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

Aquí hay un ejemplo con varios métodos que logran la sobrecarga de funciones.

Un cartel mencionó esto

La página de GNU en los complementos dice que las twigs no elegidas aún pueden generar errores de syntax, pero no veo cómo los tipos no coincidentes son errores de syntax.

Los errores de syntax a los que se refieren, creo que son las advertencias del comstackdor que recibe porque después del preprocesamiento, el comstackdor puede ver que los tipos de los argumentos de algunas funciones, aunque nunca puedan llamarse, son incorrectos. La solución (que creo que es bastante clara) es encontrar una forma de ocultar los tipos del comstackdor. La forma obvia es varargs, la forma menos obvia es la respuesta actual a la pregunta del OP.

Se aplican advertencias, es decir, no todas las soluciones son de tipo seguro y esto es completamente específico para GNU …

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

La fuente está en github …

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

El método de cambio con múltiples argumentos se puede encontrar aquí …

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

El conjunto

La advertencia se puede suprimir haciendo algún tipo de casting en la sección #define , pero creo que esto probablemente no sea la mejor o incluso una buena solución …

Cambie las llamadas de función en la sección #define a esto:

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

Sin embargo, realmente espero que alguien encuentre una solución mejor, porque esto simplemente se siente mal …

Intereting Posts