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

查看:114
本文介绍了不透明的类型可分配在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结构美孚opaqueType;

现在只用指针 opaqueType 的接口可以建立,而用户程序永远需要知道的结构美孚

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.

一个解决办法是分配一个空壳型,如:

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

typedef结构{INT faketable [8]; } opaqueType;

上述结构实施的尺寸和取向,但不进一步进入描述什么结构确实包含。因此,保持类型的目标相匹配不透明。

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.

还要注意的是视觉,铛和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 文件中。它没有明显的问题,如果他们是同一联盟的一部分。如果市民类型包含不要紧字符

  • 如果在私有类型的所有操作都只是读,没有任何问题。仅写入会导致问题。

  • 我还怀疑的唯一功能,这是自动内联的陷入困境。

  • 问题只在-O3设定发生在GCC 4.4。 -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 对齐,你能避免使用数组严格走样问题字符,因为字符明确允许引用任何其他类型。

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 。或者甚至一个整数。

更新#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->...
}

这个方法,因为你是类型双关的指针字符你是不是打破了严格别名规则。

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

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

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