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

标签 c memory-management stack opaque-pointers

在设计 C 接口(interface)时,通常只让用户程序需要知道的内容进入公共(public)接口(interface) (.h)。

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

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

typedef struct foo opaqueType;

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

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

解决方法是分配一个“shell 类型”,例如:

typedef struct { int faketable[8]; } 不透明类型;

上面的构造强制了大小和对齐方式,但没有进一步描述结构真正包含的内容。因此它符合保持类型“不透明”的目标。

它大部分都有效。但在一种情况下 (GCC 4.4),编译器提示它破坏了严格的别名,并且生成了错误的二进制文件。

现在,我已经阅读了大量关于严格别名的文章,所以我想我现在明白它的意思了。

问题是:有没有办法定义一个不透明类型,它仍然可以在堆栈上分配,并且不会违反严格的别名规则?

请注意,我已经尝试了 union method described in this excellent article但它仍然会生成相同的警告。

另请注意,visual、clang 和 gcc 4.6 及更高版本不会提示并且可以很好地处理此构造。

[编辑] 信息补充:

根据测试,该问题只出现在以下情况:

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

最后,我的目标是C90。如果真的别无选择,也许是 C99。

最佳答案

您可以使用 max_align_t 强制对齐您可以使用 char 的数组来避免严格的别名问题自 char明确允许别名任何其他类型。

类似的东西:

#include <stdint.h>
struct opaque
{
    union
    {
        max_align_t a;
        char b[32]; // or whatever size you need.
    } u;
};

如果你想支持没有 max_align_t 的编译器,或者如果您知道真实类型的对齐要求,那么您可以为 a 使用任何其他类型 union 成员(member)。

更新:如果您的目标是 C11,那么您也可以使用 alignas() :

#include <stdint.h>
#include <stdalign.h>
struct opaque
{
    alignas(max_align_t) char b[32];
};

当然,你可以替换max_align_t使用您认为合适的任何类型。甚至是整数。

更新#2:

然后,在库中使用这种类型将遵循以下原则:

void public_function(struct opaque *po)
{
    struct private *pp = (struct private *)po->b;
    //use pp->...
}

这样,因为您正在对指向 char 的指针进行类型双关你没有违反严格的别名规则。

关于c - 可在 C 中的堆栈上分配的不透明类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31195551/

相关文章:

c - 为什么我的 strcmp 实际上没有检测到 2 个单词之间的最小值?

asp.net - 本地存储大量数据

recursion - 使用基于堆栈的深度优先搜索查找循环

c - 在c中与不同类型的对象堆叠

c - 使用管道、scanf、write 转换浮点流速度慢

c - 如何将 ieee754 double 转换为两个整数的分数?

c - 类型定义,#define

R 尽管内存似乎可用,但无法分配内存

c++ - 什么时候提供用户定义的复制构造函数和赋值运算符?

c++ - 通过复制返回局部变量 - 它是如何工作的