现在,当谈到测试这种类型时,我知道有 3 种方法:
将源文件(包含类型定义及其使用的函数)目录包含到测试源文件中。 (这是最简单的,但经常在没有任何理由的情况下劝阻)。
使公共访问器有条件可用(即,仅当在包含其标头之前定义了
LIB_TEST
时)。
创建一个单独的“lib-test.h”头文件,其中包含公共访问器。
最后两个避免使访问器成为公共 API 的一部分(我们讨论的是客户端无权了解有关不透明类型内部的任何信息,并且不应提供任何访问器的情况)。
C 中常用的方法(或好的方法)是什么?一种方式比另一种方式有更多的优点/缺点吗?
举个例子,假设我有这个
struct
:
typedef struct arena {
size_t count;
size_t capacity;
size_t current;
size_t last_alloc_size;
M_Pool *pools[];
} Arena;
以及与之相关的功能:
void arena_reset(Arena *arena)
{
for (size_t i = 0; i < arena->count; ++i) {
arena->pools[i]->offset = 0;
}
arena->current = 1;
}
现在我想断言
arena_reset()
实际上已经将所有arena的offset
的pools
字段设置为0,并将arena的current
字段设置为1。包括这个库提供的API(头文件)是没有什么好处,因为只提供了结构类型的前向声明,并且无法访问其成员。
如果您想测试源模块的内部细节(即声明为
static
的函数或对象,或仅在源模块中定义的 struct
定义),这是极少数有意义的情况之一 #include
.c 文件。
例如,如果上面的结构和函数驻留在 arena.c 中,您的测试模块可以执行如下操作:
#include <stdlib.h>
#include "arena.c"
void test_arena_reset()
{
int pool_cnt = 3;
Arena *p = malloc(sizeof *p + (pool_cnt * sizeof(M_Pool));
p->count = pool_cnt;
for (int i = 0; i < pool_cnt; i++) {
p->pools[i]->offset = 1;
}
p->current = 0;
arena_reset(p);
assert(p->current == 1);
for (int i = 0; i < pool_cnt; i++) {
assert(p->pools[i]->offset == 0);
}
}
使类型定义可用于多个翻译单元的传统机制是将它们放在标头中,每个需要定义的 TU
#include
。不透明类型没有什么不同。这只是一个问题:该类型对于哪些翻译单元是不透明的,对于哪些翻译单元不是不透明的。
如果您想提供源代码中包含的测试来穿透不透明类型的不透明性,请将类型定义放在私有标头中。让那些应该能够看到类型定义的源文件包含该标头。其他人则不然。如果项目是一个库,则私有标头不会与常规库标头一起安装。
这与问题中提出的所有选项都不同,尽管它与(1)和(3)有相似之处。特别要注意的是
所讨论的私有标头将是真正的标头——没有函数定义。它将提供以前不透明类型的定义,而不是源文件来执行此操作。
除了提供的任何访问器函数外,没有定义或需要任何访问器函数。