typedef opaque指向不透明指针的指针

时间:2017-03-02 13:20:02

标签: c pointers typedef opaque-pointers

我收到了以下代码:

// file external_module.h
typedef externaldata * externalhdl; // opaque pointer
externalhdl external_Create();

// file internal_module.h
typedef internaldata * internalhdl; // opaque pointer
internalhdl internal_Create();

我想要做的是使用外部模块的不透明指针作为我的模块内部的不透明指针来保存unsasary allocs。目前,我的解决方法是:

typedef struct {externalhdl e} internaldata;

internalhdl internal_Create()
{
    internalhdl p = (internaldata*) malloc (sizeof(internaldata));
    p.e = external_Create();
    return p;
}

我想做的是使用类似的东西:

typedef ??? internaldata; //Don't know how 

internalhdl internal_Create()
{
    return external_Create();
}

从我的观点来看,它应该是可能的,因为两者都是指针,但我需要免费提醒吗?谢谢你的帮助。

2 个答案:

答案 0 :(得分:0)

在我看来,你需要考虑的最重要的事情是,除了做这样的事情之外你绝对不会得到任何东西,并且你想要typedef指向另一种指针的指针。如果它是一个不透明的poitner,它对typedef也没有意义,因为你永远不会访问底层结构的成员,它可能很好地作为void *指针传递,但是当你分配它,你必须知道它的类型,因为编译器需要知道它的大小和布局,以便正确分配它(正确对齐它,例如,否则)。

如果您不想重复使用sizeof运算符来分配正确的大小,则有两种可能的方法 1

  1. 使用宏

    #define allocate(x) x = malloc(sizeof(*x))
    

    然后

    my_type *x;
    allocate(x);
    

    但这很糟糕且不清楚。

  2. 使用分配功能

    my_type *
    my_type_alloc()
    {
        return malloc(sizeof(my_type));
    }
    

    这样

    my_type *x;
    x = my_type_allocate();
    

    这很干净简单,你做错了。

  3. 请注意,返回适当的指针类型只会确保您不会意外地执行可能导致未定义行为的事情,但分配函数可以简单地返回void *并且它们将起作用,这就是为什么我没有强制转换{{ 1}}的返回值。

    语法糖是你必须非常小心的东西,因为当你所做的是隐藏重要信息时,看起来你简化和改进了语法,这些信息会从同事程序员那里读取你的代码,程序员甚至可能是你自己的一些写完代码后的时间。

    您的解决方法实际上导致了一次不必要的分配。事实上,当你最终理解poitners时,你将真正避免不必要的分配,因为当你只读取它时,不会复制数据。

    1 在这两种情况下,您应该在执行分配后检查malloc(),以确保您可以访问此类指针而不会导致未定义的行为

答案 1 :(得分:0)

看起来你的设计走在正确的轨道上,这只是实施的问题。正如评论中所提到的,你永远不应该隐藏在typedef后面的指针,而opaque指针也不例外。如果调用者认为这些是已分配的变量,他们可能会决定做这样的愚蠢的事情:

set_obj(obj1, "foo"); // set private data to something
memcpy(&obj2, &obj1); // take a hardcopy of the data (or so we thought)
set_obj(obj1, "bar"); // set private data to something else
print_obj(obj2);      // prints "bar", wtf!!!

所以停止隐藏指针。 稍作修改,您应该让代码按预期工作:

external.h

typedef struct external_t external_t;

external_t* external_create (/* parameters here */);

external.c

#include "external.h"

external_t* external_create (/* parameters here */)
{
  external_t* ext = malloc(sizeof *ext);
  /* initialize stuff here */
  return ext;
}

internal.h

#include "external.h"

typedef struct internal_t internal_t;

internal_t* internal_create (/* parameters here */);

internal.c

#include "internal.h"

struct internal_t
{
  external_t* ext;
};

internal_t* internal_create (/* parameters here */)
{
  internal_t* inter = malloc(sizeof *inter);
  inter->ext = external_create (/* parameters here */);
  if(inter->ext == NULL)
  {
    return NULL;
  }
  /* initialize stuff here */
  return inter;
}

调用者也必须使用指针。

此外,无需转换malloc的结果。在这里击败死马:
Do I cast the result of malloc?