在C中的堆栈上可分配的不透明类型

Cya*_*yan 11 c stack memory-management opaque-pointers

在设计C接口时,通常只允许.h用户程序需要知道的公共接口().

因此,例如,如果用户程序不需要知道它们,则结构的内部组件应该保持隐藏.这确实是一种很好的做法,因为结构的内容和行为将来可能会发生变化,而不会影响界面.

实现该目标的一个好方法是使用不完整的类型.

typedef struct foo opaqueType;

现在opaqueType可以构建仅使用指针的接口,而无需用户程序知道内部工作struct foo.

但有时,可能需要静态地(通常在堆栈上)分配此类结构,以解决性能和内存碎片问题.显然,上面的结构,opaqueType是不完整的,所以它的大小是未知的,所以它不能静态分配.

解决方法是分配"shell类型",例如:

typedef struct { int faketable[8]; } opaqueType;

上面的构造强制执行大小和对齐,但不会进一步描述结构真正包含的内容.因此它符合保持"不透明"类型的目标.

它主要起作用.但在一种情况下(GCC 4.4),编译器抱怨它打破了严格别名,并且它生成了错误的二进制文件.

现在,我已经阅读了大量关于严格混叠的内容,所以我想我现在明白这意味着什么.

问题是:有没有办法定义一个opaque类型,它仍然可以在堆栈上分配,而不会破坏严格的别名规则?

请注意,我已经尝试了这篇优秀文章中描述union方法,但它仍然会生成相同的警告.

另请注意,visual,clang和gcc 4.6及更高版本不会抱怨并且可以正常使用此构造.

[编辑]信息补充:

根据测试,问题只发生在以下情况:

  • 私人和公共类型不同.我正在将公共类型转换为.c文件中的私有类型.如果他们是同一个联盟的一部分,那显然无关紧要.公共类型是否包含无关紧要char.
  • 如果私有类型的所有操作都只是读取,则没有问题.只有写入会导致问题.
  • 我还怀疑只有自动内联的函数才会遇到麻烦.
  • 问题仅发生在gcc 4.4 at -O3设置上.-O2很好.

最后,我的目标是C90.也许C99如果真的没有选择.

jxh*_*jxh 1

private您想要的是C 中C++ 访问控制的某种等效项。如您所知,不存在这样的等效项。你给出的方法大约就是我会做的。但是,我将使opaqueType实现该类型的内部组件变得不透明,因此我将被迫将其转换为内部组件中的真实类型。强制转换不应生成您提到的警告。

尽管使用起来很麻烦,但您可以定义一个接口,为不透明类型提供“堆栈分配”内存,而无需公开大小结构。这个想法是,实现代码负责堆栈分配,用户传入回调函数来获取指向分配类型的指针。

typedef struct opaqueType_raii_callback opqaueType_raii_callback;
struct opaqueType_raii_callback {
    void (*func)(opqaueType_raii_callback *, opqaueType *);
};
extern void opaqueType_raii (opaqueType_raii_callback *);
extern void opaqueType_raii_v (opaqueType_raii_callback *, size_t);


void opaqueType_raii (opaqueType_raii_callback *cb) {
    opaqueType_raii_v(cb, 1);
}

void opqaueType_raii_v (opaqueType_raii_callback *cb, size_t n) {
    opaqueType x[n];
    cb->func(cb, x);
}
Run Code Online (Sandbox Code Playgroud)

上面的定义看起来有点深奥,但这是我通常实现回调接口的方式。

struct foo_callback_data {
    opaqueType_raii_callback cb;
    int my_data;
    /* other data ... */
};

void foo_callback_function (opaqueType_raii_callback *cb, opaqueType *x) {
    struct foo_callback_data *data = (void *)cb;
    /* use x ... */
}

void foo () {
    struct foo_callback_data data;
    data.cb.func = foo_callback_function;
    opaqueType_raii(&data.cb);
}
Run Code Online (Sandbox Code Playgroud)