`
及缘南烗
  • 浏览: 6598 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

函数指针浅谈 -----表与函数指针完成命令行参数解析

阅读更多

函数指针浅谈 -----表与函数指针完成命令行参数解析

  个人认为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;

}
分享到:
评论

相关推荐

    API之网络函数---整理网络函数及功能

    EndPage 用这个函数完成一个页面的打印,并准备设备场景,以便打印下一个页 EndPagePrinter 指定一个页在打印作业中的结尾 EnumForms 枚举一台打印机可用的表单 EnumJobs 枚举打印队列中的作业 EnumMonitors ...

    powerbuilder

    参数printjobnumber:用PrintOpen()函数打开的打印作业号fontnumber:指定该打印作业使用字体的字体编号,该编号与PrintDefineFont()函数中定义的编号应该对应,字体编号的有效取值在1到8之间,0表示使用打印机的...

    C语言课件—指针

    指针变量作为函数参数(复习) 函数的指针和指向函数的指针变量 指针数组和指向指针的指针 堆内存的使用(指针数组实现动态数组) main函数的命令行参数

    指针与数据操作

    内容很全面,可以更好的理解指针.其中涉及到指针基本概念与操作、指针变量的运算与类型、与指针有关的一些问题...程序与存储空间、数据缓冲区、函数与数据接口机制、字符串数组、C语言命令行参数、定义类型、函数指针。

    关于main函数两个参数

    c语言中命令行参数argc,argv 关键词: argc,argv main(int argc,char **argv) argv为指针的指针 argc为整数

    精通Windows.API-函数、接口、编程实例.pdf

    5.6.1 标准C内存管理函数与Windows内存管理API的关系 149 5.6.2 功能性区别 149 5.6.3 效率的区别 149 第6章 进程、线程和模块 150 6.1 基本概念 150 6.1.1 应用程序与进程 150 6.1.2 控制台应用程序与...

    goA-Z:一个学习golang的小项目

    从AZ变成地鼠这是一个学习golang的小项目。 它在源文件中包含注释。该项目涵盖了Golang中的以下主题...O-命令行参数Go-P-命令行标志Go-Q-加密,MD5,SHA1 Go-R-Base64编码/解码Go-S-URL解析Go-T-环境变量Go-U-生成,执

    第8章 指针.ppt

    8.1指针与指针变量 8.2指针与函数 8.3指针与数组 8.4指针与字符串 8.5指针数组与命令行参数 8.6程序举例

    C 命令行参数

    命令行参数是使用 main() 函数参数来处理的,其中,argc 是指传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数。下面是一个简单的实例,检查命令行是否有提供参数,并根据参数执行相应的动作: #...

    C程序设计语言_第2版(带书签目录)

    5.10 命令行参数 5.11 指向函数的指针 5.12 复杂声明 第六章 结构 6.1 结构的基本知识 6.2 结构与函数 6.3 结构数组 6.4 指向结构的指针 6.5 自引用结构 6.6 表查找 6.7 类型定义(typedef) 6.8 联合 ...

    精通WindowsAPI 函数 接口 编程实例

    5.6.1 标准C内存管理函数与Windows内存管理API的关系 149 5.6.2 功能性区别 149 5.6.3 效率的区别 149 第6章 进程、线程和模块 150 6.1 基本概念 150 6.1.1 应用程序与进程 150 6.1.2 控制台应用程序...

    csdn 翁恺 C 语言程序设计(完) 视频.txt

    P496.0.3 编程练习解析4-2:九九乘法表 P506.0.4 编程练习解析4-3:统计素数求和 P516.0.5 编程练习解析4-4:猜数游戏 P526.0.6 编程练习解析5-0:n项求和 P536.0.7 编程练习解析5-1~5-3 P546.1.1 数据类型:数据...

    指针实验实验报告.doc

    } 源程序修改替换 下面源程序的功能是,通过函数指针和菜单选择来调用字符串拷贝函数或字符串连接函 数。请在程序中的下划线处填写合适的表达式、语句或代码片段来完善该程序。 源程序: #include &lt;stdio.h&gt; #...

    Linux-Socket-服务器编程实例.pptx

    Linux Socket服务器端编程实例 #include&lt;netdb.h&gt; Unix和Linux特有的头文件,主要定义了与网络有关的结构、变量类型、宏、函数等。所以在进行Socket网络编程时,必须要包含这个头文件。 5 Linux-Socket-服务器编程...

    C++大学教程,一本适合初学者的入门教材(part1)

    18.4 使用命令行参数 18.5 对编译多个源文件程序的说明 18. 6 用edt和atexit终止程序的执行 18.7 volatile类型限定符 18.8 整数和浮点数常量的后缀 18.9 信号处理 18.10 动态内存分配:函数calloc和realloc ...

    深入浅出mfc

    2.Project-&gt;Setting-&gt;Debug可以加入命令行参数。 3.在SDK中要加入"windows.h"和stdio.h。因为LoadCursor,MessageBox等函数的声明在这个文件中。 4.创建一个完整的窗口的四个步骤SDK,1设计窗口类,2注册窗口类,3...

    新概念C语言.李一波(带详细书签).pdf

    15.3 带命令行参数的主函数(指针数组做main函数的形参) 166 15.3.1 指针数组 166 15.3.2 指针数组做main函数的形参 167 习题 169 第16章 文件 171 16.1 文件指针 171 16.2 流式文件操作 172 16.3 文件定位...

    C语言大纲及课件

     了解:命令行参数。  ⑼ 结构与联合  掌握:结构定义;结构变量的定义、引用、初始化;结构数组定义、引用、初始化。  理解:动态数据结构和静态数据结构的区别;指向结构的指针、结构与函数。引用自身的结构,...

Global site tag (gtag.js) - Google Analytics