C语言陷阱与技巧第32节,有些函数的参数是结构体指针型,为什么要这么用?为什么要使用结构体指针型参数?

在C语言程序开发中,遇到复杂问题需要描述时,最常使用的就是结构体了。事实上,如果某个函数的参数比较多,并且这些参数被使用的频率比较高,为了C语言代码的简洁,也常将这些参数封装为结构体。

“重复的C语言代码”

如果函数的参数比较多,很容易产生“重复C语言代码”,例如:

int get_video(char **name, long *address, int *size, time_t *time, int *alg)
{
    ...
}
int handle_video(char *name, long address, int size, time_t time, int alg)
{
    ...
}
int send_video(char *name, long address, int size, time_t time, int alg)
{
    ...
}

上述C语言代码定义了三个函数:get_video() 用于获取一段视频信息,包括:视频的名称,地址,大小,时间,编码算法。然后 handle_video() 函数根据视频的这些参数处理视频,之后 send_video() 负责将处理后的视频发送出去。下面是一次调用:

char *name = NULL;
long address;
int size, alg;
time_t time;

get_video(&name, &address, &size, &time, &alg);
handle_video(name, address, size, time, alg);
send_video(name, address, size, time, alg);

从上面这段C语言代码来看,为了完成视频的一次“获取”——“处理”——“发送”操作,C语言程序不得不定义多个变量,并且这些变量需要重复写至少三遍。

使用结构体精简代码

虽说C语言程序的代码风格因人而异,但是“重复的代码”永远是应尽力避免的,原因本专栏已经分析多次。不管怎么说,每次使用这几个函数,都需要定义很多临时变量,总是非常麻烦的。所以,这种情况下,完全可以使用C语言的结构体语法:

struct video_info{
    char *name;
    long address;
    int size;
    int alg;
    time_t time;
};

定义好 video_info 结构体后,上述三个C语言函数的参数可以如下写,请看:

int get_video(struct video_info *vinfo)
{
    ...
}
int handle_video(struct video_info *vinfo)
{
    ...
}
int send_video(struct video_info *vinfo)
{
    ...
}

修改后的C语言代码明显精简多了,在函数内部,视频的各个信息可以通过结构体指针 vinfo 访问,例如:

printf("video name: %s\n", vinfo->name);
long addr = vinfo->address;
int size = vinfo->size;

事实上,使用结构体 video_info 封装视频信息的各个参数后,调用这几个修改后的函数也是非常简洁的:

struct video_info vinfo = {0};

get_video(&vinfo);
handle_video(&vinfo);
send_video(&vinfo);

从上述C语言代码可以看出,使用修改后的函数只需定义一个临时变量,整个代码变得非常精简。

为何使用结构体指针?

读者应该注意到了,修改之前的 handle_video() 和 send_video() 函数原型如下:

int handle_video(char *name, long address, int size, time_t time, int alg);
int send_video(char *name, long address, int size, time_t time, int alg);

根据这段C语言代码,我们知道 handle_video() 和 send_video() 函数只需要读取参数信息,并不再修改参数,那为什么使用结构体 video_info 封装数据,修改后的 handle_video() 和 send_video() 函数参数是 struct video_info * 指针型呢?

int handle_video(struct video_info *vinfo);
int send_video(struct video_info *vinfo);

既然 handle_video() 和 send_video() 函数只需要读取参数信息,那我们就无需再使用指针型了呀?的确如此,这两个函数的参数直接使用 struct video_info 型也是可以的:

int handle_video(struct video_info vinfo)
{
    ...
}
int send_video(struct video_info vinfo)
{
    ...
}

似乎这种写法和使用 struct video_info * 指针型 参数的区别,无非就是函数内部访问数据的方式改变了而已。但是,如果读者能够想到我们之前讨论过的C语言函数的“栈帧”概念,应该能够发现,使用指针型参数的 handle_video() 和 send_video() 函数效率更好,开销更小。

因为指针型的参数少了拷贝到自己栈帧的过程,指针型参数的 handle_video() 和 send_video() 函数直接使用 vinfo 变量。不过与此同时,在 handle_video() 和 send_video() 函数返回之前,vinfo 不能被释放,这一点我们之前也讨论过,读者如果感到陌生,可以再回头看看本专栏之前的文章。

更详细的分析可以参考我之前的文章《》。

小结

本节主要介绍了C语言结构体语法封装函数参数的小技巧,借助这个小技巧,C语言程序员能够写出更加精简的代码。在文章最后,我们还讨论了使用结构体指针型参数的特点,合理的使用指针,能够进一步的减小C语言程序的开销,并在此基础上进一步的提升效率。

阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif