函数在C中使用GCC重载 - 编译器警告

问题描述:

我试图在C中实现函数重载,而且我非常接近。我正在使用C99,因此在C11中引入的_Generic关键字不适用于我。我已经开发了一些工作代码,但是当我编译它时,我收到了一些警告。函数在C中使用GCC重载 - 编译器警告

工作例如:

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

编译创建以下警告:

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 

对于多一点的调试信息,这里是主要的功能是什么样子的预处理程序所做的工作后:

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

我该如何使编译警告消失而sti会有工作代码吗?

+0

我相信它调用引起警告的'print_string(1)'和'print_int(“this”)',但这些调用不应该发生,因为类型不匹配。 – tjwrona1992

+0

而不是选择'print_int(x)'或'print_string(x)',如果您选择'print_int'或'print_string'并将所选函数(指针)应用于x,会出现什么情况? – user2357112

+0

@ user2357112,我会怎么做呢?我对函数指针不太擅长。 – tjwrona1992

从理论上讲,这应该工作:

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

它选择print_intprint_string,然后将所选函数应用于x

+1

已确认使用gcc 4.9和clang 3.5 – Leandros

+0

这很好,当指定的类型不受支持时,会触发编译器错误。 –

+0

是的,这是行不通的。谢谢! – tjwrona1992

警告可以通过执行在#define节某种类型的铸造被抑制,但我觉得这可能不是最好的,甚至一个很好的解决方案在所有...

更改功能在#define调用部分这样的:

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

我真的希望有人用更好的解决方案出现,但因为这只是感觉不对......

+0

我刚刚提出了相同的想法,但它只会给你一个不同的警告:'-Winter-to-int-cast'。 – Leandros

+0

我用'gcc -Wall'编译它,并且它摆脱了警告。但是使用'g ++'编译会完全失败,并带来很多错误。 – tjwrona1992

+2

它在C++中失败,因为按照gcc的文档,在C++中都没有可用的内置函数。 – Leandros

构建插件上的GNU page表示未选择的分支可能仍会生成语法错误,但我无法看到错误类型是如何出现语法错误的。

无论如何,当您将参数移出函数的类型相关选项时,您可以摆脱警告。因此(在以伪代码,使其更具可读性),而不是

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

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

这就是user2357112在评论建议。我正在研究类似的解决方案,但是我很难得到默认部分(上面的pass)。当我使用(void),然后应该扩展到(void)(x),我得到一个关于不匹配的括号的错误。

下面的解决方案创建一个不使用其参数的默认打印功能。它可能可能是一个不存在的函数,所以在链接或其他产生错误的地方会出现问题。

#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; 
} 
+0

'(void)'不起作用,因为我们选择的是一个表达式,而不是一个标记序列,'(void)'不是一个完整的表达式。 – user2357112

+0

@ user2357112:好点。无论如何,在默认子句中生成编译器错误可能是更好的方法。 –

下面是一个有几个方法实现函数重载的例子。

其中一张海报提到这个

在构建插件的GNU页说,树枝没有选择可能 仍然产生语法错误,但我看不出 类型不匹配的是如何在语法错误。

他们所指的语法错误,我相信是编译器警告你,因为预处理的编译器可以看到参数类型某些功能,即使他们不能被称为是错误的之后得到的。解决方案(我认为非常简洁)是找到一种方法来隐藏编译器中的类型。显而易见的方法是可变参数,不太明显的方式是OP的问题的当前答案。

告诫:即不是所有的解决方案是类型安全的,这完全是特定于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; 
} 

来源是在github ...

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

开关法多个参数可以在这里找到...

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

整个