我们有一个匿名类型,typedef
ed 为 void *
,它是 API 的句柄(所有代码都在 C11 中)。它是故意的 void *
因为它所指向的内容会根据我们编译的平台而变化,而且我们也不希望应用程序尝试取消引用它。在内部,我们知道它应该指向什么,并适本地转换它。这很好,代码是公开的,我们已经使用它很多年了,无法更改。
问题是我们现在需要引入其中的另一个,我们不希望用户将两者混淆,我们希望如果错误的句柄传递给我们的函数之一,编译器会抛出错误。然而,到目前为止我尝试过的所有 C 编译器的所有版本(GCC、Clang、MSVC)都不在乎;他们知道底层类型是void *
,所以一切都会发生(这是使用-Wall
和-Werror
)。换句话说,我们的typedef
没有实现任何目标,我们还不如只是使用了void *
。我也尝试过 Lint 和 CodeChecker ,他们似乎也不关心(尽管你可能会质疑我的配置)。请注意,我无法使用 -Wpedantic
,因为我们包含了无法实现的第三方代码。
我尝试将新事物设为特定的 typedef
ed 指针,而不是 void *
但这并不能完全解决问题,因为编译器仍然对调用者将新的特定 typedef
指针传递到需要现有句柄 typedef
的现有函数中。
是否有(a)一种方法来构造一个新的匿名句柄,以便编译器不允许将其传递给现有函数,或者(b)我们可以应用一个检查器来解决问题,至少在我们自己使用这些 API?
下面是一些代码来说明问题:
#include <stdlib.h>
typedef struct {
int contents;
} existingThing_t;
typedef void *anonExistingHandle_t;
typedef struct {
char contents[10];
} newThing_t;
typedef void *anonNewHandle_t;
typedef newThing_t *newHandle_t;
static void functionExisting(anonExistingHandle_t handle)
{
existingThing_t *pThing = (existingThing_t *) handle;
// Perform the function
(void) pThing;
}
static void functionNew(anonNewHandle_t handle)
{
newThing_t *pThing = (newThing_t *) handle;
// Perform a new function
(void) pThing;
}
int main() {
anonExistingHandle_t existingHandle = NULL;
anonNewHandle_t newHandleA = NULL;
newHandle_t newHandleB = NULL;
functionExisting(existingHandle);
functionNew(newHandleA);
// These should result in a compilation error
functionExisting(newHandleA);
functionNew(existingHandle);
functionExisting(newHandleB);
return 0;
}
最佳答案
Is there (a) a way to construct a new anonymous handle such that the compiler will not allow it to be passed to the existing functions
是的,使用无法隐式转换为 void *
的类型。使用结构。
typedef struct {
struct newThing_s *p;
} anonNewHandle_t;
无论如何,您的设计存在缺陷并且禁用了所有静态编译器检查。不要使用 void *
,而是使用结构体或内部带有 void *
的结构体,以启用编译检查。研究非常非常标准的FILE *
是如何工作的。 FILE
不是 void
。
不要使用 typedef 指针。它们非常令人困惑。 https://wiki.sei.cmu.edu/confluence/display/c/DCL05-C.+Use+typedefs+of+non-pointer+types+only
我建议重写您的库,以便您不使用 void *
也不使用 typedef 指针。
设计可能如下所示:
// handle.h
struct handle_s;
typedef struct {
struct handle_s *p;
} handle_t;
handle_t handle_init(void);
void handle_deinit(handle_t t);
void handle_do_something(handle_t t);
// handle.c
struct handle_s {
int the_stuff_you_need;
};
handle_t handle_init(void) {
return (handle_t){
.p = calloc(1, sizeof(struct handle_s))
};
}
void handle_do_something(handle_t h) {
struct hadnle_s *t = h->p;
// etc.
}
// anotherhandle.h
// similar to above
typedef struct {
struct anotherhandle_s *p;
} anotherhandle_t;
void anotherhandle_do_something(anotherhandle_t h);
// main
int main() {
handle_t h = handle_new();
handle_do_something(h);
handle_free(h);
anotherhandle_do_something(h); // compiler error
}
关于C 编译器检查 typedef'ed void *,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72415062/