【发布时间】:2012-04-16 16:06:00
【问题描述】:
我有一个旨在存储用户定义数据(即来自插件)的结构。它有一个这样的char[],具有给定的最大大小来存储该数据。
struct A
{
// other members omitted
// data meant to be type punned, only contains PODs
char data[256];
};
然后是一个示例用户结构,它有一个静态函数可以从A 转换自身。
struct B
{
int i;
double d;
static B& FromA_ref(A& a)
{
// static_assert that sizeof(B) < sizeof(A::data)
return * reinterpret_cast<B*>(a.data);
}
};
我使用g++ -O3 -std=c++0x -Wall -o test test.cpp (GCC 4.6.1) 进行编译。
这会触发dereferencing type-punned pointer will break strict-aliasing rules 警告。我认为这没问题,因为我使用了 char[] 作为存储空间,我认为它遵循与 char* 相同的规则。我觉得奇怪的是它没有。不是吗?嗯,...我现在不能改变它,所以让我们继续吧。
现在让我们考虑以下方法:
struct B
{
....
static B* FromA_ptr(A& a)
{
// static_assert that sizeof(B) < sizeof(A::data)
return reinterpret_cast<B*>(a.data);
}
}
由于我没有在此处取消引用任何内容,因此 GCC 不会输出任何警告。当我稍后使用指向B 的指针时也不会。
A a;
auto b = B::FromA_ptr(a);
b->i = 2; // no warnings.
但是这样做安全吗?我觉得我一直在努力解决问题,而不是解决问题。对我来说,-> 仍在以某种方式取消引用变量。
或者,有没有更好的方法来达到这个效果? IE。从另一个结构内的存储中获取可修改的引用(或指针)? (Union 将不起作用,因为在定义 A 时不知道存储的类型集,并且可能通过插件添加一些类型,memcpy 将迫使我来回复制数据,尽管它似乎是到目前为止唯一安全的方式)
【问题讨论】:
-
我不是专家,但您在寻找
__may_alias__属性吗? blog.worldofcoding.com/2010/02/… -
不管怎样,对齐问题怎么处理?
-
@curiousguy :到目前为止我还没有,但我应该这样做。不过,在 x86 上,我想我可能会在最坏的情况下降低性能。我希望
__attribute__((aligned(8)));就足够了,因为我不想自动矢量化任何东西。可能,may_alias已经告诉 GCC 在做太多奇怪的事情之前要注意对齐。 -
@curiousguy:一个简单的方法应该是
union { char dat[theSize]; typeWithWorstAlignment dummy; }。这将解决所有问题,但标准没有提供解决方案的混叠问题。鉴于缺乏任何别名问题的解决方案,我觉得奇怪的是 C11 标准包含对齐指令,这些指令在涉及类型双关的情况下并不是真正有用的except。
标签: c++ type-punning