10

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

 3 years ago
source link: https://blog.popkx.com/c%E8%AF%AD%E8%A8%80%E9%99%B7%E9%98%B1%E4%B8%8E%E6%8A%80%E5%B7%A7%E7%AC%AC32%E8%8A%82-%E6%9C%89%E4%BA%9B%E5%87%BD%E6%95%B0%E7%9A%84%E5%8F%82%E6%95%B0%E6%98%AF%E7%BB%93%E6%9E%84%E4%BD%93/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在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语言程序的开销,并在此基础上进一步的提升效率。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK