c++ - 读/写部分分配的对齐内存

标签 c++ memory language-lawyer sse memory-alignment

很多关于访问未分配内存的问题,这显然是未定义的行为。但是下面的极端情况呢。

考虑以下结构,它对齐到 16 个字节,但只占用其中的 8 个字节:

struct alignas(16) A
{
    float data[2]; // the remaining 8 bytes are unallocated
};

现在我们通过 SSE 对齐加载/存储内在函数访问 16 个字节的数据:

__m128 test_load(const A &a)
{
    return _mm_load_ps(a.data);
}

void test_store(A &a, __m128 v)
{
    _mm_store_ps(a.data, v);
}

这也是未定义的行为吗?我应该改用填充吗?

无论如何,由于英特尔内在函数不是标准 C++,访问部分分配但对齐的内存块(不大于对齐的大小)是标准 C++ 中的未定义行为吗?

我同时处理了固有情况和标准 C++ 情况。我对他们两个都很感兴趣。

最佳答案

另见 Is it safe to read past the end of a buffer within the same page on x86 and x64?这个问题的阅读部分基本上是重复的。

根据 ISO C++ 标准,它是 UB,但我认为像这样的只读访问在提供英特尔内在函数(可以自由定义任何额外的他们想要的行为)。它在 asm 中绝对是安全的,但风险在于,优化将 UB 转换为错误编译代码的 C++ 编译器可能会导致问题,如果它们能够证明那里没有任何内容可读的话。在链接的问题上有一些讨论。


在对象之外写入总是不好的。不要这样做,即使您放回之前阅读的相同垃圾也不行:非原子加载/存储对可能是一个问题,具体取决于您的结构后面有哪些数据。

唯一可以的情况是在一个数组中,您知道接下来会发生什么,并且有未使用的填充。例如使用由 4B 重叠的 16B 存储写出一个 3-float 结构数组。 (没有用于过度对齐的 alignas,因此数组将它们打包在一起而没有填充)。


3 个 float 的结构比 2 个 float 更好。

对于这个特定示例(2 个 float ),您可以只使用 MOVSD 执行 64 位零扩展加载,并使用 MOVSD 或 MOVLPS 执行 __m128< 的低半部分的 64 位存储.

关于c++ - 读/写部分分配的对齐内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41152964/

相关文章:

c++ - 是否可以在未计算的上下文中从 STD 形成指向不可寻址函数的指针?

c++ - 如何将c++中的类划分为hpp和cpp文件

C++:类成员函数作为事件回调

c# - 如何存储数十亿个 JSON 文件并进行查询

c++ - Windows - SDL_PumpEvents 重置为系统光标

c - 如何将多个结构体连续放入内存?

c++ - 重载解决方案:是否首选直接转换运算符(作为复制省略的结果)?

iphone - iOS模拟内存警告问题

performance - PHP 读取大文本文件

c - 通过结构别名数组