可在 C 中的堆栈上分配的不透明类型 [英] Opaque types allocatable on stack in C

查看:10
本文介绍了可在 C 中的堆栈上分配的不透明类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When designing a C interface, it is common to let into the public interface (.h) only what needs to be known by the user program.

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

Hence for example, the inner components of structures should remain hidden if the user program does not need to know them. This is indeed good practice, as the content and behavior of the struct could change in the future, without affecting the interface.

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

A great way to achieve that objective is to use incomplete types.

typedef struct foo opaqueType;

现在可以构建一个只使用指向 opaqueType 的指针的接口,而用户程序不需要知道 struct foo 的内部工作.

Now an interface using only pointers to opaqueType can be built, without the user program ever needing to know the inner working of struct foo.

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

But sometimes, it can be required to allocate such structure statically, typically on stack, for performance and memory fragmentation issues. Obviously, with above construction, opaqueType is incomplete, so its size is unknown, so it cannot be statically allocated.

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

A work around is to allocate a "shell type", such as :

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

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

Above construction enforces a size and an alignment, but doesn't go farther into describing what the structure really contains. So it matches the objective of keeping the type "opaque".

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

It mostly works. But in one circumstance (GCC 4.4), the compiler complains that it breaks strict-aliasing, and it generates buggy binary.

现在,我已经阅读了大量有关严格别名的内容,所以我想我现在明白它的含义了.

Now, I've read a ton of things about strict aliasing, so I guess I understand now what it means.

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

The question is : is there a way to define an opaque type which can nonetheless be allocated on stack, and without breaking strict aliasing rule ?

请注意,我尝试了本文中描述的 联合方法很棒的文章,但它仍然会产生同样的警告.

Note that I've attempted the union method described in this excellent article but it still generates the same warning.

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

Note also that visual, clang and gcc 4.6 and later don't complain and work fine with this construction.

信息补充:

根据测试,只有以下几种情况才会出现问题:

According to tests, the problem only happens in the following circumstances :

  • 私有和公共类型不同.我在 .c 文件中将公共类型转换为私有类型.他们是否属于同一个工会显然并不重要.公共类型是否包含 char 无关紧要.
  • 如果对私有类型的所有操作都只是读取,那是没有问题的.只有写入会导致问题.
  • 我还怀疑只有自动内联的函数会遇到麻烦.
  • 问题仅发生在 gcc 4.4 的 -O3 设置上.-O2 很好.
  • Private and public type different. I'm casting the public type to private inside the .c file. It doesn't matter apparently if they are part of the same union. It doesn't matter if the public type contains char.
  • If all operations on private type are just reads, there's no problem. Only writes cause problems.
  • I also suspect that only functions which are automatically inlined get into trouble.
  • Problem only happens on gcc 4.4 at -O3 setting. -O2 is fine.

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

Finally, my target is C90. Maybe C99 if there really is no choice.

推荐答案

您可以使用 max_align_t 强制对齐,并且可以使用 char 因为明确允许 char 为任何其他类型设置别名.

You can force the alignment with max_align_t and you can avoid the strict aliasing issues using an array of char since char is explicitly allowed to alias any other type.

类似的东西:

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

如果你想支持没有max_align_t的编译器,或者如果你知道真实类型的对齐要求,那么你可以使用任何其他类型的a 工会成员.

If you want to support compiler that do not have the max_align_t, or if you know the alignment requirements of the real type, then you can use any other type for the a union member.

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

UPDATE: If you are targetting C11, then you may also use alignas():

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

当然,您可以将 max_align_t 替换为您认为合适的任何类型.甚至是整数.

Of course, you can replace the max_align_t with whatever type you think appropriate. Or even an integer.

更新 #2:

那么,在库中使用这种类型将是:

Then, the use of this type in the library would be something along the lines of:

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

这样,由于您对指向 char 的指针进行类型双关语,因此您不会违反严格的别名规则.

This way, since you are type-punning a pointer to char you are not breaking the strict aliasing rules.

这篇关于可在 C 中的堆栈上分配的不透明类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆