首页 > 编程笔记 > C语言笔记 阅读:2

C语言接口设计技巧(新手必看)

本节介绍 C 语言接口设计中常用的一些方法和技巧。

接口对称设计

C语言的接口都是成对出现的,代表着一个操作以及对应的反操作。比如 malloc() 的反操作是 free()。

下表给出了设计对称接口时常用的术语,这些术语通常作为函数名的前缀或后缀存在。

表:设计对称接口时常用的术语
操作 反操作 含义或用途
new delete 创建/销毁一个新对象,通常意味着存在内存分配;如 variant_new 和 variant_delete
create destroy 创建/销毁一个新对象,通常意味着存在内存分配;如 create_window 和 destroy_window
init deinit/terminate/cleanup 初始化/清理一个对象;如 array_init 和 array_cleanup
open close 打开/关闭一个对象;如 fopen 和 fclose
connect disconnect 连接/断开;如 connect_to_host 和 disconnect_from_host
read write 读取/写入;如 fread 和 fwrite
alloc free 分配/释放;如 malloc 和 free
ref unref 引用/反引用;如 variant_ref 和 variant_unref
get set 获取/设置;如 get_cookie 和 set_cookie
attach detach 附着/脱离;如 attach_data 和 detach_data

接口的参数和返回值

有关接口的参数和返回值,下面给出一些值得遵循的建议。

首先,函数接口应尽量避免返回 void 类型。若分析标准 C 库提供的接口,就会发现仅有少量函数的返回值为 void 类型,常见的便是 free(),而绝大多数的标准库函数是有返回值的。

某些函数通过返回一些特殊的值来表明出错状态,而某些函数的返回值纯粹是为了方便使用。比如 memcpy()、strcpy() 等复制内存或字符串的函数,会返回传入的目标地址值,这样可以方便调用者书写代码。

实质上,对 C 程序来讲,从函数中返回一个值对程序性能的影响微乎其微。因此,我们将函数中已经计算好的值返回,可避免调用者再次计算这些值。

比如,BSD 系统(包括 macOS)提供了 stpcpy() 和 stpncpy() 函数,这两个函数的功能与 strcpy() 和 strncpy() 一样,但返回值不同。stpcpy() 和 stpncpy() 函数会返回目标缓冲区中指向 \0 终止字符的指针。这样,当我们需要将多个字符串依次串接到同一个缓冲区中时,调用 stpcpy() 要比调用 strcpy() 高效很多,可以避免每次串接操作均从目标缓冲区的头部开始数起,如下面的代码所示:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
 
int main(void)
{
    /* 代码将在buffer中构造“foobar” */
    char buffer[20];
    char *to = buffer;
 
    to = stpcpy(to, "foo");
    to = stpcpy(to, "bar");
    printf("%s\n", buffer);
    return 0;
}

其次,应选择最合适的参数类型。比如当涉及长度、大小等参数时,应使用 size_t 类型。

因为习惯,很多人可能会选择 int 或 unsigned int 类型来表示长度或大小等参数。现在应摒弃这种做法,因为 64 位系统已经很常见了,一个文件的长度可以轻松超过 int 或 unsigned int 类型的最大存储值。而 size_t 类型是无符号整型,其定义随底层架构的不同而不同(基本等同于 uintptr_t 类型),它的最大存储值对应操作系统可处理的最大文件长度,故而比 int 或 unsigned int 类型更加安全。

再次,对指针类参数和返回值,一定要恰当使用 const 修饰词。虽然对 C 代码来讲,const 指针可以随意被强制转换为非 const 指针,但它仍然可以在一定程度上帮助我们书写更好的代码,原因有两个:
最后,应谨慎使用 bool 类型的返回值或参数。当一个函数在执行中可能出现多种错误时,只能用于表示成功或失败的 bool 型返回值就不够用了。

另外,我们经常使用 bool 型参数来传递一个标志,当一个标志不够用时,就必须使用更多的 bool 型参数;而如果我们使用 int 或 unsigned 类型的参数作为标志,则可以通过标志位来传递多达 32 个标志,这将在扩展这一接口时带来极大的便利。

相关文章