使用GCC在C中重载函数-编译器警告
我正试图在C中实现函数重载,我非常接近。我使用C99,因此C11中引入的使用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
\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;
}