无参函数的应用与限制

无参函数的应用与限制

在 C90 标准中,你可以声明一个无参数信息的函数。一个示例如下:

	void no_arg_func();

使用空的小括号来表示没有参数信息,编译器无法获取到参数信息,也就不会进行参数检查,因此你可以传递任意数量的参数。下面是一个具体的应用。

	#include <stdio.h>
	#include <stdarg.h>
	
	#define MAXARGC 2
	
	#define TEST_BEGIN() \
	  printf("some variable initialized, or something else\n")
	
	#define TEST_END() \
	  printf("some teardown procedure, or something else\n");
	
	/* function prototype */
	extern int init_data(const char *name, int id);
	extern char *find_name(int id);
	extern int find_id(const char *name);
	extern int destroy_data(int id);
	
	typedef void (*func_t)();
	
	extern void execute_a_test(func_t text_func, int count, ...);
	
	int main(int argc, char *argv[])
	{
	  execute_a_test((func_t)init_data, 2, "test", -5);
	  execute_a_test((func_t)find_name, 1, -5);
	  execute_a_test((func_t)find_id, 1, "test");
	  execute_a_test((func_t)destroy_data, 1, -5);
	  
	  return 0;
	}
	
	int init_data(const char *name, int id)
	{
	  printf("name is %s, id is %d, %s\n", name, id, __func__);
	}
	
	char *find_name(int id)
	{
	  printf("id is %d, %s\n", id, __func__);
	}
	
	int find_id(const char *name)
	{
	  printf("name is %s, %s\n", name, __func__);
	}
	
	int destroy_data(int id)
	{
	  printf("id is %d, %s\n", id,  __func__);
	}
	
	void execute_a_test(func_t test_func, int count, ...)
	{
	  long argument[MAXARGC];
	  int i = 0;
	  va_list ap;
	  
	  if (test_func == NULL) {
	    return;
	  }
	
	  va_start(ap, count);
	  for (; i < count; i++) {
	    argument[i] = va_arg(ap, long);
	  }
	  va_end(ap);
	
	  TEST_BEGIN();
	  (*test_func)(argument[0], argument[1]);
	  TEST_END();
	}

在上面的代码中,我需要测试四个函数,这四个函数的测试过程大同小异,它们最大的区别在于参数个数的不同。在这里我使用无参函数将四个待测试函数强转后作为参数传入到 execute_a_test 中,通过可变长参数统一不同参数,以最长的参数个数来调用函数,不区分指针与值,由于 test_func 没有参数信息,因此我们可以传递任意个数的参数,多余的参数子函数不会使用,不会造成问题。

execute_a_test 函数可以进行如下修改:

	void execute_a_test(func_t test_func, int count, ...)
	{
	  long argument[MAXARGC];
	  int i = 0;
	  va_list ap;
	  
	  if (test_func == NULL) {
	    return;
	  }
	
	  va_start(ap, count);
	  for (; i < count; i++) {
	    argument[i] = va_arg(ap, long);
	  }
	  va_end(ap);
	
	  TEST_BEGIN();
	  if (count == 1) {
	    (*test_func)(argument[0]);
	  } else if (count == 2) {
	    (*test_func)(argument[0], argument[1]);
	  }
	  TEST_END();
	}

这个修改避免了传递多余参数的问题,但是加入的条件分支会降低程序的性能。

无参函数是 c 语言的旧标准中支持的特性,新标准虽然能够兼容旧标准,但最好不要使用无参函数。这样我们对上述程序再次进行修改,改为不使用无参函数的实现。

	#include <stdio.h>
	#include <stdarg.h>
	
	#define TEST_BEGIN()                                        \
	  printf("some variable initialized, or something else\n")
	
	#define TEST_END() \
	  printf("some teardown procedure, or something else\n");
	
	/* function prototype */
	extern int init_data(const char *name, int id);
	extern char *find_name(int id);
	extern int find_id(const char *name);
	extern int destroy_data(int id);
	
	typedef int (*func_one)(long);
	typedef int (*func_two)(long, long);
	
	extern void execute_a_test(func_two func, long arg1, long arg2);
	extern void execute_one_arg_functest(func_one func, long arg);
	extern void execute_two_arg_functest(func_two func, long arg1, long arg2);
	
	int main(int argc, char *argv[])
	{
	  execute_a_test((func_two)init_data, (long)"test", (long)-5);
	  execute_a_test((func_two)find_name, (long)-5, (long)0);
	  execute_a_test((func_two)find_id, (long)"test", (long)0);
	  execute_a_test((func_two)destroy_data, (long)-5, (long)0);
	
	  execute_two_arg_functest((func_two)init_data, (long)"test", (long)-5);
	  execute_one_arg_functest((func_one)find_name, (long)-5);
	  execute_one_arg_functest((func_one)find_id, (long)"test");
	  execute_one_arg_functest((func_one)destroy_data, (long)-5);
	  
	  return 0;
	}
	
	int init_data(const char *name, int id)
	{
	  printf("name is %s, id is %d, %s\n", name, id, __func__);
	}
	
	char *find_name(int id)
	{
	  printf("id is %d, %s\n", id, __func__);
	}
	
	int find_id(const char *name)
	{
	  printf("name is %s, %s\n", name, __func__);
	}
	
	int destroy_data(int id)
	{
	  printf("id is %d, %s\n", id,  __func__);
	}
	
	void execute_a_test(func_two func, long arg1, long arg2)
	{
	  if (func == NULL) {
	    return;
	  }
	
	  TEST_BEGIN();
	  (*func)(arg1, arg2);
	  TEST_END();
	}
	
	void execute_one_arg_functest(func_one func, long arg)
	{
	  if (func == NULL) {
	    return;
	  }
	
	  TEST_BEGIN();
	  (*func)(arg);
	  TEST_END();
	}
	
	void execute_two_arg_functest(func_two func, long arg1, long arg2)
	{
	  if (func == NULL) {
	    return;
	  }
	
	  TEST_BEGIN();
	  (*func)(arg1, arg2);
	  TEST_END();
	}
	

上面的代码中,使用了多次强转,这是一大不足。实际上可以将指针与值分开,编写单独的函数,但这样又会增强代码的耦合度。写来写去还是觉得使用可变长参数可能更好点!最终版函数如下:

	void execute_a_test(func_t test_func, int count, ...)
	{
	  long argument[MAXARGC];
	  int i = 0;
	  va_list ap;
	
	  if (test_func == NULL) {
	    return;
	  }
	
	  va_start(ap, count);
	  for (; i < count; i++) {
	    argument[i] = va_arg(ap, long);
	  }
	  va_end(ap);
	
	  TEST_BEGIN();
	  if (count == 1) {
	    (*(func_one)test_func)(argument[0]);
	  } else if (count == 2) {
	    (*(func_two)test_func)(argument[0], argument[1]);
	  }
	  TEST_END();
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值