函数指针浅谈 -----表与函数指针完成命令行参数解析
个人认为C语言的精妙在于宏,指针。这使的C语言既可以与底层硬件打交道,又可以完成上层复杂的构架设计。而函数指针又是指针的一朵绚烂绽放的花。
所谓函数指针,就是一个指向函数地址的指针变量,虽然这只是一个变量,但是在C语言中,这个变量可以做很多事情。
下面是一个函数指针的声明:
void (* param_handler) (char *value);
大家可以看到
param_handler
变量是指向下面函数类型的指针变量,这样,只要函数式满足下列条件,那么
param_handler就
可以指向它,执行指向的函数
void func (char *value);
在命令行参数解析和执行中,我们常常要对不同的参数和参数带的value进行解析,通常我们用if-elseif-else语句来处理,但是这样会使判断条件很长,代码的可读性很差,而且当我们需要加新功能时,会使代码更加乱。
我们可以分析一下,对不同参数的处理函数是不是大致长的差不多?可不可以抽象出来,提取一个公共的函数模板,然后让实现放在后面?
这个时候,函数指针就派上用场了。在C++中便是虚函数了。
当然,光函数指针是不够的,不然还是要在main函数中if-elseif-else,我们需要和参数绑定,这样我们可以循环地枚举,当匹配参数时,执行相应的函数。
下面是这个表元素的声明:
typedef struct
{
char short_param[2];
char full_param[64];
void (* param_handler) (char *value);
bool_t need_value;
} parameter_t;
下面是main函数中的枚举:
int main(int argc, char **argv)
{
int i, j;
for(j=1; j<argc; j++)
{
for(i=0; i<array_max_len(parameter_t); i++)
{
if(str_equal(param_array[i].short_param, argv[j]) ||
str_equal(param_array[i].full_param, argv[j]))
{
if(param_array[i].need_value)
{
param_array[i].param_handler(argv[++j]);
}
else
{
param_array[i].param_handler("");
}
}
}
}
return 0;
}
现在,在main函数的逻辑中,我们并知道有什么参数,相应的逻辑是什么?这样低耦合就满足,下面就是面向功能的实现了。
我们有如下需求:打印程序的版本,提供程序的帮助。以下我们可以轻松实现
void show_version(char *value)
{
printf("This is a test version 1.0-*T*\n");
}
void show_help(char *value)
{
printf("==============================\n");
printf("-v --version: show version of this\n");
printf("-h --help: show help of this\n");
printf("==============================\n");
}
现在我们需要绑定参数和参数的执行函数,我们可以在下面数据结构表的定义中定义。
下面是参数结构表:
^_^,我们可以执行了
#define parameter_t_max_c 2
parameter_t param_array[parameter_t_max_c] = {
{.short_param = "-v",
.param_handler = show_version,
.full_param = "--version",
.need_value = FALSE,
},
{
"-h", "--help", show_help, FALSE
},
};
neilhhw@neilhhw-laptop:/tmp$ ./test -v
This is a test version 1.0-*T*
neilhhw@neilhhw-laptop:/tmp$ ./test -v -h
This is a test version 1.0-*T*
==============================
-v --version: show version of this
-h --help: show help of this
-p --print: print the param value you input
==============================
根据需求我们需要一个打印用户输入的功能,那么我们只需要加一个针对这个功能的函数,然后新加一个绑定。完全不用动main函数的代码~~
void print_value(char *value)
{
printf("The value you input is: %s\n", value);
}
#define parameter_t_max_c 3
parameter_t param_array[parameter_t_max_c] = {
{.short_param = "-v",
.param_handler = show_version,
.full_param = "--version",
.need_value = FALSE,
},
{
"-h", "--help", show_help, FALSE
},
{
"-p", "--print", print_value, TRUE
},
};
附上全部代码:
#include <stdio.h>
typedef unsigned char bool_t;
#define TRUE 1
#define FALSE 0
typedef struct
{
char short_param[2];
char full_param[64];
void (* param_handler) (char *value);
bool_t need_value;
} parameter_t;
#include <stdlib.h>
#define str_equal(x, y) (strncmp(x, y, strlen(y)) == 0 ? 1 : 0)
#define array_max_len(x) x##_max_c
void show_version(char *value)
{
printf("This is a test version 1.0-*T*\n");
}
void show_help(char *value)
{
printf("==============================\n");
printf("-v --version: show version of this\n");
printf("-h --help: show help of this\n");
printf("-p --print: print the param value you input\n");
printf("==============================\n");
}
void print_value(char *value)
{
printf("The value you input is: %s\n", value);
}
#define parameter_t_max_c 3
parameter_t param_array[parameter_t_max_c] = {
{.short_param = "-v",
.param_handler = show_version,
.full_param = "--version",
.need_value = FALSE,
},
{
"-h", "--help", show_help, FALSE
},
{
"-p", "--print", print_value, TRUE
},
};
int main(int argc, char **argv)
{
int i, j;
for(j=1; j<argc; j++)
{
for(i=0; i<array_max_len(parameter_t); i++)
{
if(str_equal(param_array[i].short_param, argv[j]) ||
str_equal(param_array[i].full_param, argv[j]))
{
if(param_array[i].need_value)
{
param_array[i].param_handler(argv[++j]);
}
else
{
param_array[i].param_handler("");
}
}
}
}
return 0;
}