C语言可变长参数实现“多态”

一、问题来源


先看看困惑来来源:

C语言可变长参数实现“多态”_第1张图片

这让我很疑惑,难道c也支持“多态”的特性么?貌似没见过呀~


二、解决方案


google帮忙,明白了一二,特此记录:

原来这种“多态”是通过c语言的可变长参数实现的(python也具有这种特性)

有关可变长参数的介绍见文章末尾的参考列表,说的很详细。

截取关键的内容:

1.可变长参数的宏定义:

(学习宏函数的典例呀)

// stdarg.h
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
// vadefs.h
typedef char *  va_list;
#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )
#define _ADDRESSOF(v)        ( &(v) )
#define _INTSIZEOF(n)        ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

2.可变长参数的宏介绍:

C语言可变参数通过三个宏(va_start、va_end、va_arg)和一个类型(va_list)实现,

void va_start ( va_list ap, paramN );
参数:
ap: 可变参数列表地址
paramN: 确定的参数
功能:初始化可变参数列表(把函数在 paramN 之后的参数地址放到 ap 中)。

void va_end ( va_list ap );
功能:关闭初始化列表(将 ap 置空)。

type va_arg ( va_list ap, type );
功能:返回下一个参数的值。

va_list :存储参数的类型信息。

好了,综合上面3个宏和一个类型可以猜出如何实现C语言可变长参数函数:用 va_start 获取参数列表(的地址)存储到 ap 中,用 va_arg 逐个获取值,最后用 va_arg 将 ap 置空。

按照说明,我实现了一个简单的测试代码,来测试可变长参数:

/*************************************************************************
 * @File Name:    test.c
 * @Author:       kehr
 * @Mail:         [email protected]
 * @Created Time: 2013年11月30日 星期六 19时06分32秒
 * @Copyright:    GPL 2.0 applies
 * @Purpose:      测试可变长参数,实现c的“多态”              
 *************************************************************************/
#include 
#include 

void show(int first_param,int flag, ...);	

int main()
{
	show(1,2,3,4,5);

    return 0;
}

void show(int first_param,int flag, ...)
{
	//定义参数列表
	va_list vl;
	
	//初始化参数列表
	va_start (vl, flag);

	//获取参数值
	printf ("%d ",first_param);
	printf ("%d ",flag );
	printf("%d ",va_arg(vl,int));
	printf("%d ",va_arg(vl,int));
	printf("%d ",va_arg(vl,int));
	printf("\n");

	//关闭参数列表
	va_end(vl);

}

那么这个清楚了以后,用来实现c的“多态”就好办了。修改上面的代码,实现“多态”:

/*************************************************************************
 * @File Name:    test.c
 * @Author:       kehr
 * @Mail:         [email protected]
 * @Created Time: 2013年11月30日 星期六 19时06分32秒
 * @Copyright:    GPL 2.0 applies
 * @Purpose:      测试可变长参数,实现c的“多态”              
 *************************************************************************/
#include 
#include 
#define _NAME 0
#define _NAME_AGE 1

void show(int first_param,int flag, ...);	//对外暴露的接口
void showName(char* name);					//内部的实现
void showNameAndAge(char* name, int age);	//内部的实现

int main()
{
	//如果不看show的具体实现,那么下面这两句代码不就是“多态”了么?
	show(1,_NAME,"xiaogqiang");
	show(2,_NAME_AGE,"xiaoqiang",23);

    return 0;
}

void show(int first_param,int flag, ...)
{
	//这里地一个参数没有做处理,完全可以直接输出,或进行其它处理
	printf("%d\n",first_param);
	

	//定义参数列表
	va_list vl;

	//需要处理的参数
	char* name;
	int age;
	
	//初始化参数列表
	va_start (vl, flag);

	//获取参数值
	//printf("flag=%d\n",flag);
	//printf("name=%s\n",va_arg(vl,char*));
	//printf("age=%d\n",va_arg(vl,int));
	//单独使用下面这条语句无法得到结果,猜测是printf的内部原因。
	//printf("name=%s\n age=%d\n",va_arg(vl,char*),va_arg(vl,int));
	
	
	//根据标志选择要处理的函数
	switch(flag)
	{
		case _NAME:
			showName(va_arg(vl,char*));
			break;
		case _NAME_AGE:
			name = va_arg(vl,char*);
			age = va_arg(vl,int);
			showNameAndAge(name,age);
			break;
		default:
			printf("没有匹配的函数!\n");
	}

	//关闭参数列表
	va_end(vl);


}

void showName(char* name)
{
	printf("name=%s\n",name);
}

void showNameAndAge(char* name, int age)
{
	printf("name=%s\nage=%d\n",name,age);
}

结果如下:

C语言可变长参数实现“多态”_第2张图片


三、IDE


(我用的是vim编辑的,可能界面有些人会不习惯。上张我的vim编辑图)

C语言可变长参数实现“多态”_第3张图片

感兴趣的朋友,我可以把我的vimrc共享,目前文件配置超过600行,分割了一下感觉好点了。

vim初用很难受,用久了就月来越离不开了。程序员编程利器,建议学一下。


四、总结


        通过这个例子的测试,我知道C的强大也是毋庸置疑的。面向过程的语言也可以借用面向对象的思想,二者没有绝对的鸿沟。对于C来说,某个方面可能不擅长,但是并不但表做不了。还有许多好玩儿的特性,待我慢慢去挖出来。

        这个例子中的思想在c的很多函数都有所体现,除了文章开头介绍的open函数外还有很多。说明了在C的标准实现里面这些特性占据着很重要的的地位。借用面向对象的思想解决问题,这也便是面向过程和面向对象的结合。

        最近要写点对面向对象的思考。是时候总结一下了。


五、参考


http://www.cnblogs.com/chinazhangjie/archive/2012/08/18/2645475.html

http://club.topsage.com/thread-2263309-1-1.html有关


你可能感兴趣的:(C/C++)