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

使用GCC在C中重载函数-编译器警告,c,c-preprocessor,compiler-warnings,c99,overloading,C,C Preprocessor,Compiler Warnings,C99,Overloading,我正试图在C中实现函数重载,我非常接近。我使用C99,因此C11中引入的\u Generic关键字对我不可用。我已经开发了一些工作代码,但是当我编译它时,我得到了一些警告 工作示例: #include <stdio.h> #define print(x) \ __builtin_choose_expr(__builtin_types_comp

我正试图在C中实现函数重载,我非常接近。我使用C99,因此C11中引入的
\u Generic
关键字对我不可用。我已经开发了一些工作代码,但是当我编译它时,我得到了一些警告

工作示例:

#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;
}
要了解更多的调试信息,以下是预处理器完成工作后主函数的外观:

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

我如何才能使编译警告消失,并且仍然有工作代码?

可以通过在
#define
部分执行一些类型转换来抑制警告,但我觉得这可能不是最好的解决方案,甚至根本不是一个好的解决方案

#define
部分中的函数调用更改为:

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

我真的希望有人能想出更好的解决方案,因为这感觉不对…

理论上,这应该是可行的:

#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\u int
print\u string
,然后将所选函数应用于
x

,内置程序上说,未选择的分支仍可能生成语法错误,但我看不出不匹配的类型是如何产生语法错误的

无论如何,当您将参数从依赖于类型的选项中移到函数时,可以消除警告。因此(在伪代码中,以使其更可读),而不是

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

这就是user2357112在评论中的建议。我正在研究一个类似的解决方案,但我很难让默认部分(上面的
过程
)正常工作。当我使用
(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;
}
#包括
#定义打印(x)\
__内置型选择扩展(内置型兼容型)\
int),print_int\
__内置型选择扩展(内置型兼容型)\
常量字符[]),打印字符串\
打印(如有)(x)
无效打印_int(int i){
printf(“int:%d\n”,i);
}
无效打印字符串(常量字符*s){
printf(“char[]:%s\n”,s);
}
作废打印(如有){
printf(“未知\n”);
}
内部主(空)
{
int n=9;
const char str[]=“你好”;
打印(n);
打印(str);
印刷品(1);
打印(“本”);
印刷品(3.2);
返回0;
}

下面是一个示例,其中包含几种实现函数重载的方法

一张海报提到了这一点

内置程序上的GNU页面说,未选择的分支可能会 仍然会生成语法错误,但我无法看到不匹配的类型 是语法错误

他们所指的语法错误我相信是你得到的编译器警告,因为在预处理后,编译器可以看到某些函数的参数类型是错误的,即使它们永远不会被调用。解决方案(我认为这很简单)是找到一种对编译器隐藏类型的方法。最明显的方式是varargs,不太明显的方式是OP问题的当前答案

注意事项适用ie不是所有的解决方案都是类型安全的,这是完全特定于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;
}
#包括
#包括
#包括
#定义打印(x)\
(\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
__内置选择导出(uuuu内置类型兼容p(typeof(x),char[]),打印字符串\
(无效)0)(x)
#定义print1(x)\
__内置选择导出(内置类型兼容)(typeof(x,int),打印(1,x)\
__内置选择导出(内置类型兼容)(typeof(x),char[]),打印字符串1(1,x)\
(无效)0)
#定义print2(x)\
__内置打印机选择expr(内置类型兼容p(typeof(x),int),打印机(1,x)\
__内置打印机选择expr(内置类型兼容)(typeof(x),char[]),打印机(2,x)\
(无效)0)
#定义类型\ ID(x)\内置类型\兼容类型\ p(类型(x),int)*1\
+内置类型兼容类型(typeof(x),char[])*2
#定义print3(x)打印机(类型_ID(x),x)
#定义STATIC_ASSERT(COND,MSG)typedef char STATIC_assertion_35;#MSG[(COND)?1:-1]
#定义print4(x)\
静态断言(类型ID(x),\uuuuu行\uuuuu)\
打印机(类型_ID(x),x)
无效打印机(int i,…){
清单五;
va_启动(v,i);
开关(一){
案例1:{
int arg=va_arg(v,int);
printf(“int:%d\n”,arg);
va_端(v);
打破
}
案例2:{
char*arg=va_arg(v,char*);
printf(“字符*:%s\n”,arg);
va_端(v);
打破
}
默认值:{
fprintf(stderr,“未知类型,中止”);
中止();
}
}
}
无效打印_int(int i){
printf(“int:%d\n”,i);
}
无效打印字符串(字符*s){
printf(“字符*:%s\n”,s);
}
无效打印\u int1(int i,…){
清单五;
va_启动(v,i);
int arg=va_arg(v,int);
printf(“int:%d\n”,arg);
va_端(v);
}
无效打印字符串1(int i,…){
清单五;
va_启动(v,i);
char*arg=va_arg(v,char*);
printf(“字符*:%s\n”,arg);
va_端(v);
}
int main(int argc,char*argv[]){
int-var=1729;
双变量1=1729;
//类型安全
//打印(var1);//完成时间错误
打印(var);
印刷品(“印刷品”);
/*以下内容不是类型安全的*/
print1(var1);//坏……什么也不做。
print1(var);
打印1(“打印1”);
print2(var1);//坏……什么也不做。
print2(var);
打印2(“打印2”);
//打印3
#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;
}
#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;
}