访问POD结构数组作为其单个成员的数组是否违反了严格的别名?

时间:2015-02-15 18:20:18

标签: c++ c++11 struct c++03 strict-aliasing

我有整数值,用于访问不相关数据存储中的数据,即句柄。我已选择将整数包装在结构中以便具有强类型对象,以便不能混合不同的整数。他们是,而且必须是POD。这就是我正在使用的:

struct Mesh {
    int handle;
};
struct Texture {
    int handle;
};

我有这些句柄的数组,例如:Texture* textureHandles;

有时我需要将句柄数组作为int*传递给代码的更通用部分。现在我正在使用:

int* handles = &textureHandles->handle;

它本质上是一个指向struct的第一个元素的指针,并将其解释为一个数组。

我的问题基本上是这是合法的,还是违反了严格别名来操纵指向同一内存的int* handlesTexture* textureHandles。我认为这应该被允许,因为在两种情况下都以相同的方式访问基础类型(int)。我的保留与以下事实有关:我通过在一个结构中获取成员的地址来访问多个结构。

作为我的第一个问题的延伸,以下是否可以?

int* handles = reinterpret_cast<int*>(textureHandles);

3 个答案:

答案 0 :(得分:10)

reinterpret_cast<int*>(textureHandles)绝对和&textureHandles->handle一样好。标准中有一个特殊的例外,继承自C even,它表示指向适当转换的标准布局结构的指针指向该结构的初始成员,反之亦然。

使用它来修改句柄也没关系。它没有违反别名规则,因为您使用类型为int的左值来修改int类型的子对象。

增加结果指针,并使用它来访问Texture个对象数组中的其他元素,但有点不确定。 Jerry Coffin已经指出sizeof(Texture) > sizeof(int)有可能。但是,即使sizeof(Texture) == sizeof(int),指针算法仅针对指向数组的指针定义(其中任意对象可以被视为长度为1的数组)。你在任何地方都没有int的数组,因此添加内容是未定义的。

答案 1 :(得分:5)

不,这不能保证有效。特别是,允许​​编译器在结构的任何元素之后插入填充,但不允许在数组的元素之间插入填充。

那就是说,只有一个元素(类型int的结构,或者至少那么大的结构,例如long),大多数编译器赢得的机会都很大。插入任何填充,因此您当前的使用情况通常相当安全。

答案 2 :(得分:1)

它肯定违反了严格的别名,如果该功能可以访问 您可以通过int*Mesh*Texture*来排列数组 很好地遇到了问题(虽然可能只有它修改了 以某种方式排列。)

根据您对问题的描述,我不会考虑规则 严格的别名确实是你所关心的。真正的问题 是编译器是否可以添加填充到不是的结构 出现在int中,以便sizeof( Mesh ) > sizeof( int )。和 虽然答案是正式肯定的,我无法想象一个编译器 这样做,至少在今天,至少在int或更大的类型中 struct。 (一个单词寻址的机器可能会添加填充到一个 仅包含struct的{​​{1}}。)

真正的问题可能更多的是通用代码是否 遗产,不能改变或不改变。否则,明显的解决方案 是创建一个通用句柄类型:

char

然后从中派生您的类型,或使用struct Handle { int handle; }; 如你所愿。有(或至少是)允许的保证 通过指向其他人的指针访问reinterpret_cast的成员 struct,只要成员和所有前面的成员都相同。 这就是你如何模拟C中的继承。即使是保证 已被删除 - 这是它在C ++中出现的唯一原因 是出于C兼容性的原因 - 没有编译器敢于违反 它,考虑到依赖它的现有软件的数量。 (该 例如,Python的实现。几乎所有的Python 插件,包括用C ++编写的插件。)