函数在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会有工作代码吗?
从理论上讲,这应该工作:
#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_int
或print_string
,然后将所选函数应用于x
。
警告可以通过执行在#define
节某种类型的铸造被抑制,但我觉得这可能不是最好的,甚至一个很好的解决方案在所有...
更改功能在#define
调用部分这样的:
print_string((char*)x)
print_int((int)x)
我真的希望有人用更好的解决方案出现,但因为这只是感觉不对......
我刚刚提出了相同的想法,但它只会给你一个不同的警告:'-Winter-to-int-cast'。 – Leandros
我用'gcc -Wall'编译它,并且它摆脱了警告。但是使用'g ++'编译会完全失败,并带来很多错误。 – tjwrona1992
它在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;
}
'(void)'不起作用,因为我们选择的是一个表达式,而不是一个标记序列,'(void)'不是一个完整的表达式。 – user2357112
@ 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/
整个
我相信它调用引起警告的'print_string(1)'和'print_int(“this”)',但这些调用不应该发生,因为类型不匹配。 – tjwrona1992
而不是选择'print_int(x)'或'print_string(x)',如果您选择'print_int'或'print_string'并将所选函数(指针)应用于x,会出现什么情况? – user2357112
@ user2357112,我会怎么做呢?我对函数指针不太擅长。 – tjwrona1992