通过联合合法访问 __m128 变量的字节吗?
Posted
技术标签:
【中文标题】通过联合合法访问 __m128 变量的字节吗?【英文标题】:Is accessing bytes of a __m128 variable via union legal? 【发布时间】:2013-02-23 20:14:16 【问题描述】:考虑这个变量声明:
union
struct
float x, y, z, padding;
components;
__m128 sse;
_data;
我的想法是通过x
、y
、z
字段分配值,执行SSE2计算并通过x
、y
、z
读取结果。不过,我有点怀疑它是否合法。我担心的是对齐:MSDN 说__m128
变量自动对齐到 16 字节边界,我想知道我的联合是否可以打破这种行为。
这里还有其他需要考虑的陷阱吗?
【问题讨论】:
不,对齐不是问题。工会将拥有其所有成员正常工作所需的任何对齐方式。 还要注意,至少在Visual Studio上,你可以通过sse.m128_f32[0]
、sse.m128_f32[1]
、sse.m128_f32[2]
、sse.m128_f32[3]
获取__m128 sse;
的组件,所以不需要这个把戏。
@R.MartinhoFernandes 和 gcc?
对于 gcc,您可以做更简单的操作:sse[0]
、sse[1]
等,尽管最高 4.7 只能在 C 中使用,而您需要 g++-4.8 才能在 C++ 中获得它。使用联合,对齐和别名会很好,但代码质量会很差,最好使用((float*)&sse)[1]
。
附带说明,SSE 数据类型不应该以这种方式访问。因此,这样做通常会导致显着的性能损失。仅在打包/解包数据并且对打包数据有很多工作要做时才这样做。
【参考方案1】:
联合的对齐应该没问题,但在 Windows 的情况下,您可能能够直接访问 32 位组件。来自xmmintrin.h
(DirectXMath
):
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128
float m128_f32[4];
unsigned __int64 m128_u64[2];
__int8 m128_i8[16];
__int16 m128_i16[8];
__int32 m128_i32[4];
__int64 m128_i64[2];
unsigned __int8 m128_u8[16];
unsigned __int16 m128_u16[8];
unsigned __int32 m128_u32[4];
__m128;
如您所见,里面有 4 个花车。如果您想成为超级偏执狂,您可能可以定义所有相同的对齐特性等,以确保不会破坏任何东西。但是,据我所知,鉴于您在回答中提到了 MSDN,您应该一切顺利。如果你知道你有 SSE 兼容的东西,联合和直接访问它都应该工作。您还可以查看 DirectXMath 标头,以了解 Windows 如何进行定义和自行处理:它们还定义了一些宏,具体取决于编译时存在的内在函数和功能。
编辑:正如 R.MartinhoFernandes 在 cmets 中所说,直接访问它可能比在联合中重新定义它更容易。
【讨论】:
我想保持我的代码跨平台,因此联合技巧。 @VioletGiraffe 那么联合应该没问题。 GCC 也应该尊重工会,也不要做任何时髦的事情,但我不是 GCC 专家,我相信一些标准律师会出现并谴责我们俩使用union
。以上是关于通过联合合法访问 __m128 变量的字节吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 16 字节的内存加载到 Rust __m128i 中?