如何在 C 中使用不透明指针



我正在在线浏览 C 书,我不明白结构指针上的 6.6。我正在尝试在初始化函数中返回指向双向链表的指针,但迷失了方向。

.h 有一个不透明的指针指向引用双向链表:

typedef void * d_link_list_t;

.c 实现具有列表结构定义:

    typedef struct list_s
    {
        node_t * head;
        node_t * tail;
        int count; //num nodes
    } list_t

.c后来我实现了初始化函数,其中问题是:

d_link_list_t* Initialize(void)
{
     //Converting opaque pointer to real pointer
      d_link_list_t* list = (d_link_list_t*)malloc(sizeof(d_link_list_t*));

     // Now make concrete list_t pointer and set the members
      list_t  * rlP;//real list pointer
      rlP = (list_t*)malloc(sizeof(list_t));
      rlP->head = NULL;
     rlP->tail = NULL;
     rlP->count = 1;
     //cast opaque pointer to real list P PROBLEM HERE
     list = (d_link_list_t*)rlP;
      list->count = 0; //list IS NOT STRUCT
      return list;
}

我想返回 * d_link_list_t ,一个不透明的指针,它将引用链表的实例。我希望 implementation.c 中的所有函数都使用 .h 中这个不透明指针引用的列表。 我根本不明白该怎么做。

我尝试只是将不透明指针投射到 list_t 结构指针 - 期望不透明指针指向与结构指针相同的位置,但这似乎是错误的。尝试使用"->"访问计数会给出错误"尝试在非结构或联合中访问成员'count'">

如何使空不透明指针引用我的list_t结构?请帮帮我!

你的代码有几个问题。首先,d_link_list_t已经是一个空指针,所以当你定义你的不透明指针时,使用

d_link_list_t list; //list is a void pointer
and not
d_link_list_t* list; //list is a pointer to a void pointer.

其次,我认为这段代码

//Converting opaque pointer to real pointer
d_link_list_t* list = (d_link_list_t*)malloc(sizeof(d_link_list_t*));

应该为不透明的指针分配空间,但你不需要这样做,正如我之前所说,只需使用

d_link_list_t list; //list is a void pointer.

第三,当您将真实指针投射到不透明指针时,您还需要在函数结束时调整转换。用

list = (d_link_list_t)rlP;

而不是

list = (d_link_list_t*)rlP;
最后,

在最后,为什么要尝试通过不透明的指针访问结构的内容。为什么会这样

list->count = 0; //list IS NOT STRUCT

创建不透明指针的整个想法是使用户无法直接访问结构。如果要访问结构,请使用实指针或将不透明指针强制转换为指向结构的指针。同样,整个想法是对函数的用户隐藏列表的内部实现。

这一行是错误的:

d_link_list_t* list = (d_link_list_t*)malloc(sizeof(d_link_list_t*));

它分配了错误的内存量。您需要分配所指向事物的大小,而不是指针的大小。

然而,无论如何,这是一个坏主意。该函数应为:

d_link_list_t Initialize(void)
{
// Now make concrete list_t pointer and set the members
    list_t  * rlP;
    rlP = malloc(sizeof(*rlP));
    rlP->head = NULL;
    rlP->tail = NULL;
    rlP->count = 1;        
    return rlP;
}

不确定您要用list->count = 0;做什么,因为list具有不透明类型,这是不可能的。 也不清楚你为什么写rlP->count = 1而不是= 0.

如果要使用指针语法(即 d_link_list_t * (,则应从 typedef 行中删除*

你不需要(void *),你应该简单地使用

typedef struct list_s list_t;

,然后在 .c 文件中定义struct list_s

不透明的指针类似于 C FILE结构。在 Microsoft C 中,FILE结构为

typedef struct _iobuf {
    void *_Placeholder;
} FILE;

请注意,没有实际字段,唯一的成员是void *。此指针实际上指向位于 Microsoft C 实现深处的秘密结构。假设它看起来像这样

typedef struct {
    int cnt;
    char *ptr;
    char *base;
    int flag;
    int fd;
} impfile;

然后,对FILE指针进行操作的函数将_Placeholder成员强制转换为impfile结构。例如,访问文件描述符的函数如下所示:

int getfd(FILE *fp)
{
    return ((impfile *) fp->_Placeholder)->fd;
}

Windows API 通过句柄使用类似的技术,如 HWND

此方法的优点是用户无法访问任何私有成员。这也允许 API 在不破坏任何现有代码的情况下进行更改,因为您知道没有人可以篡改结构的私有结构。

这也可以在使用句柄正文习惯用法应用于C++。

最新更新