C 编译器检查 typedef'ed void *

标签 c typedef void

我们有一个匿名类型,typedefed 为 void *,它是 API 的句柄(所有代码都在 C11 中)。它是故意的 void * 因为它所指向的内容会根据我们编译的平台而变化,而且我们也不希望应用程序尝试取消引用它。在内部,我们知道它应该指向什么,并适本地转换它。这很好,代码是公开的,我们已经使用它很多年了,无法更改。

问题是我们现在需要引入其中的另一个,我们不希望用户将两者混淆,我们希望如果错误的句柄传递给我们的函数之一,编译器会抛出错误。然而,到目前为止我尝试过的所有 C 编译器的所有版本(GCC、Clang、MSVC)都不在乎;他们知道底层类型是void *,所以一切都会发生(这是使用-Wall-Werror)。换句话说,我们的typedef没有实现任何目标,我们还不如只是使用了void *。我也尝试过 Lint 和 CodeChecker ,他们似乎也不关心(尽管你可能会质疑我的配置)。请注意,我无法使用 -Wpedantic,因为我们包含了无法实现的第三方代码。

我尝试将新事物设为特定的 typedefed 指针,而不是 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/

相关文章:

c - 如果进程在 MPI_Recv 上挂起,则 MPI C fprintf() 输出不会显示

C 无法从 fifo(命名管道)读取

c - 带指针的 typedef 声明

c - 使用一个函数作为另一个函数的参数时的“error: invalid use of void expression”

c++ - 'void' 编译器 : TDM-GCC 4. 6.1 64 位之前的预期主表达式

c - 针对旧版 Windows,可以使用什么来代替 getaddrinfo() 和 freeaddrinfo()?

c - 重命名函数而不更改其引用

c++ - 如何在 C++ 中声明自引用容器?

c++ - 只允许特定的 `typedef` 作为函数参数

c++ - 将 Void 作为指针传递给类,然后执行其内容