使用 GCC 在 C 中重载函数 - 编译器警告
Function overloading in C using GCC - compiler warnings
我正在尝试在 C 中实现函数重载,而且我非常接近。我使用的是 C99,所以 C11 中引入的 _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;
}
编译会产生以下警告:
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;
}
我怎样才能让编译警告消失并且仍然有工作代码?
可以通过在 #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_int
或 print_string
,然后将所选函数应用到 x
。
内置的 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;
}
下面是一个示例,其中包含几种实现函数重载的方法。
一位发帖人提到了这个
The GNU page on the build-ins says that the branches not chosen may
still generate syntax errors, but I fail to see how mismatched types
are syntax errors.
我相信他们提到的语法错误是您收到的编译器警告,因为在预处理之后,编译器可以看到某些函数的参数类型,即使它们永远不会被调用也是错误的。解决方案(我认为这很巧妙)是找到一种方法来对编译器隐藏类型。显而易见的方法是可变参数,不太明显的方法是当前对 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
可以在这里找到具有多个参数的 switch 方法...
http://locklessinc.com/articles/overloading/
整个
我正在尝试在 C 中实现函数重载,而且我非常接近。我使用的是 C99,所以 C11 中引入的 _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;
}
编译会产生以下警告:
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;
}
我怎样才能让编译警告消失并且仍然有工作代码?
可以通过在 #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_int
或 print_string
,然后将所选函数应用到 x
。
内置的 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;
}
下面是一个示例,其中包含几种实现函数重载的方法。
一位发帖人提到了这个
The GNU page on the build-ins says that the branches not chosen may still generate syntax errors, but I fail to see how mismatched types are syntax errors.
我相信他们提到的语法错误是您收到的编译器警告,因为在预处理之后,编译器可以看到某些函数的参数类型,即使它们永远不会被调用也是错误的。解决方案(我认为这很巧妙)是找到一种方法来对编译器隐藏类型。显而易见的方法是可变参数,不太明显的方法是当前对 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
可以在这里找到具有多个参数的 switch 方法...
http://locklessinc.com/articles/overloading/
整个