这是否允许在c?
void hello(int a, float y)
{
int s = a + y;
printf("value in hello = %d \n",s);
}
void hello(int a, int b, int c)
{
int s = a + b + c;
printf("value in hello 2 = %d \n", s);
}
int main(void) {
// your code goes here
hello(2, 3.5);
hello(1, 2, 3);
return 0;
}
这里的功能签名不同吗?
我收到错误:
prog.c:11:6: error: conflicting types for 'hello'
void hello(int a,int b,int c)
^
prog.c:2:6: note: previous definition of 'hello' was here
void hello(int a,float y)
^
prog.c: In function 'main':
prog.c:24:2: error: too few arguments to function 'hello'
hello(2,3.5);
^
prog.c:11:6: note: declared here
void hello(int a,int b,int c)
答案 0 :(得分:4)
没有。这不被允许。 C不允许函数重载。
你最接近的是写一个variadic functions.
例如,Unix open(2)
系统调用假装以支持两个不同的接口:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
但事实上,它是一种可变函数。
答案 1 :(得分:1)
这是一个名为函数重载的功能。它不允许使用C语言。
答案 2 :(得分:1)
不允许。
C不像现代OOP(C#或Java),其中允许使用具有相同名称但签名不同的方法。
此功能称为function overloading
,在C中不可用。
你可以阅读这个
了解更多详情。
答案 3 :(得分:1)
正如其他几个海报已经说过的那样,在平原C中不支持。但是你可以使用一些技巧。如果您使用的是C11,则可以使用_Generic
个宏。当被调用函数根据参数的类型具有不同的行为时,这是可用的。
#include <stdio.h>
void hello_f( float f ){ printf("I'm a float: %f\n", f ); }
void hello_i( int i ){ printf("I'm an integer: %d\n", i ); }
#define hello(x) _Generic((x), int: hello_i, float: hello_f)(x)
int main(){
hello( 2 );
hello( 2.0f );
return 0;
}
像这样工作:
$ gcc -std=c11 generic_test.c && a.exe
I'm an integer: 2
I'm a float: 2.000000
如果签名的参数数量不同,还有另一种模仿重载行为的技巧。这个技巧可以在C99中使用,因为它使用了可变参数宏。
/* Your original functions renamed */
void hello_int_float(int a,float y){
int s = a + y;
printf("value in hello = %d \n",s);
}
void hello_int_int_int(int a,int b,int c){
int s = a + b + c;
printf("value in hello 2 = %d \n",s);
}
#define VA_WHAT_IMPL(_1, _2, _3, N, ...) N
#define VA_WHAT(...) VA_WHAT_IMPL(__VA_ARGS__, int_int_int, int_float, one_arg)
#define hello_impl2(signature_count, ...) hello_ ## signature_count (__VA_ARGS__)
#define hello_impl(what, ...) hello_impl2(what, __VA_ARGS__)
#define hello(...) hello_impl(VA_WHAT(__VA_ARGS__), __VA_ARGS__)
int main(){
hello( 2, 1.0f);
hello( 1, 3, 6);
return 0;
}
请注意,如果不支持参数数量或参数类型不正确,您会收到有用的错误消息,这种方法并不是真正安全的。 它只计算参数的数量。以下是代码扩展到的内容:
$ gcc -std=c99 -E overload.c
# 1 "overload.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "overload.c"
void hello_int_float(int a,float y){
int s = a + y;
printf("value in hello = %d \n",s);
}
void hello_int_int_int(int a,int b,int c){
int s = a + b + c;
printf("value in hello 2 = %d \n",s);
}
# 19 "overload.c"
int main(){
hello_int_float (2, 1.0f);
hello_int_int_int (1, 3, 6);
return 0;
}
我实际上在实际代码中使用了这个技巧。
答案 4 :(得分:1)
如果你编译:
// file1.c
int helloi(int a) {
return a;
}
int hellofff(float a, float b, float c) {
return a * b * c;
}
gcc -c file1.c
您可以检查输出文件的符号:
$ nm file1.o
000000000000000c T hellofff
0000000000000000 T helloi
函数名称与代码中的函数名称完全相同。这是因为C保留了用于链接的函数和全局变量名。
让我们使用重载在C ++中做同样的事情
// file2.cpp
int hello(int a) {
return a;
}
int hello(float a, float b, float c) {
return a * b * c;
}
编译并检查它的符号:
$ g++ -c file2.cpp
$ nm file2.o
000000000000000c T _Z5hellofff
0000000000000000 T _Z5helloi
它完成了我们在C中手动完成的操作。它还在前面插入了_Z5
。 _Z
表示&#34;这是一个GCC错位名称&#34;。 5
表示实际名称长度为5个字节,之后是类型。 (否则你不会告诉helloi()和hello(int)之间的区别。)
我们甚至可以称这些&#34; Mangled&#34; (技术术语)来自C的名字:
// file3.c
#include <stdio.h>
int _Z5hellofff(float a, float b, float c);
int main(void) {
printf("hello(1, 2, 3) == %d\n", _Z5hellofff(1, 2, 3));
return 0;
}
并使用:gcc -o file3 file3.c file2.o
希望它链接和运行。还有一些其他格式,例如Microsoft,Go,Rust等使用的格式。 (Rust也使用_ZNname
,但之后很难解读胡言乱语
以_Z
开头的原因是在C中,编译器/ libc保留以_Z
开头的标识,用户不应该将它们用于自己的事物(它在这里没关系,因为我们知道编译器将生成什么)。 (至少在gcc / clang中以__
开头的事情)
C ++也有名称空间,因此namespace::class::thing(int)
变为_Z20namespace5class5thingi
。