众所周知,C语言不支持函数重载,支持函数重载的是C++。究其原因,C语言在编译函数之后,将"_函数名"存放到函数库,而C++在编译函数之后,将"_函数名_参数类型_参数类型"存放到函数库
但是,在查询fcntl函数时,却发现其函数原型有多个
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
难道C语言也支持函数重载?于是我深入了解了相关知识,并将其整理分享
首先,C语言确实不支持函数重载,这种现象被称为"不定参数函数"
不定参数
我们都经常接触不定参数,因为printf就是最常见的不定参数函数,它的函数原型如下:
int printf( const char *format, ... ); //c99前
int printf( const char *restrict format, ... ); //c99起
如上所示,"…"表示不定参数,它必须写在函数列表的最后
不定参数实现原理
C语言引入了三个宏来处理不定参数的问题,如下所示:
//va_arg()、va_start()、va_end()
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1)) //类型n的大小,这是考虑了字节对齐
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //ap指向第一个不定参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址 返回当前ap指向的值,并且增加ap
#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效
type va_arg(va_list argptr, type);
void va_end(va_list argptr);
void va_start(va_list argptr, last_parm);
通过上述宏的时候,可以将函数传入堆栈的参数通过指针读取出来(通过va_start和va_arg传入的参数类型作为指针的偏移量,即可将堆栈中存放的数据取出)
示例代码
#include <stdio.h>
#include <stdarg.h>
int sum(int a, ...)
{
va_list var_ptr;
va_start(var_ptr, a);
int sum = a;
a = va_arg(var_ptr, int);
while(a != 0)
{
sum += a;
a = va_arg(var_ptr, int); //获取下一个参数值
}
va_end(var_ptr);
return sum;
}
int main()
{
int i = sum(1,2,3,4,5,6,7,8,9,0);
printf("The sum is: %d\n",i);
return 0;
}
程序运行结果:
The sum is: 45