C++ _declspec(align(16))不将指针对齐到16字节

C++ _declspec(align(16))不将指针对齐到16字节,c++,sse,C++,Sse,因此,我尝试使用SSE函数\uuuum\uLoad\u128,我对SSE非常陌生,如果我在某个地方犯了一些愚蠢的错误,请原谅我 这是密码 void one(__m128i *arr, char *temp) { // SSE needs 16 byte alignment. _declspec (align(16)) __m128i *tmp = (__m128i*) temp; if (((uintptr_t)tmp & 15) == 0) p

因此,我尝试使用SSE函数
\uuuum\uLoad\u128
,我对SSE非常陌生,如果我在某个地方犯了一些愚蠢的错误,请原谅我

这是密码

void one(__m128i *arr, char *temp)
{
    // SSE needs 16 byte alignment.
    _declspec (align(16)) __m128i *tmp = (__m128i*) temp;

    if (((uintptr_t)tmp & 15) == 0)
        printf("Aligned pointer");
    else 
        printf("%d", ((uintptr_t)tmp & 15)); // This prints as 12

    arr[0] = _mm_load_si128(tmp);
}
我在visual studio上遇到一个错误
0xC0000005:访问冲突读取位置0xFFFFFF。

0xFFFFFFFF
看起来不对,我做错了什么

arr
参数初始化为
\u m128i arr[5]={0}

另一种选择是使用
\u mm\u loadu\u 128
,它工作正常,但据我所知,它应该生成
movdqu
指令,但这是生成的程序集

    arr[0] = _mm_loadu_si128(tmp);
00D347F1  mov         eax,dword ptr [tmp]  
00D347F4  movups      xmm0,xmmword ptr [eax]  
00D347F7  movaps      xmmword ptr [ebp-100h],xmm0  
00D347FE  mov         ecx,10h  
00D34803  imul        edx,ecx,0  
00D34806  add         edx,dword ptr [arr]  
00D34809  movups      xmm0,xmmword ptr [ebp-100h]  
00D34810  movups      xmmword ptr [edx],xmm0 
谢谢各位,从答案中我意识到我犯了几个错误

  • 对齐源代码使用
    \u aligned\u malloc

  • 使用优化编译

  • 使用C++不强制C


    我在这里看到三个问题:

    <>这代码是严格的C,而不是C++。这本身不是问题,但问题被标记为C++。
  • 您无法区分指针的对齐方式与指针指向的对齐方式
  • 当代码流位于
    one
    内部时,无法更改
    arr
    temp
    的对齐方式
  • 让我们把注意力集中在第二点上——有一个指针,这就是指针指向的东西。我想你已经知道这两者的区别了

    基本上,当您编写
    \u declspec(align(16))\u_m128i*tmp
    时,您会告诉程序:

    在堆栈上分配指针
    tmp
    时,请确保
    tmp
    的第一个字节分配在可除以16的地址(堆栈上)上

    太棒了,
    tmp
    本身与16对齐,它根本不影响tmp指向的内容。您需要
    temp
    指向已对齐的数据。这可以通过以下方式完成:

  • 使用适当的
    alignas
    关键字(
    alignas(16)char my_buffer[16*100];
    )在堆栈上分配数据
  • 使用能够分配对齐数据的内存分配功能分配动态数据,如
    对齐的\u alloc
    ,或MSVC的
    \u aligned\u malloc
    ,需要
    \u aligned\u free
    。看

  • 您不能反向对齐内存,必须首先对齐内存分配。确保通过
    temp
    传递的数据已对齐,如果无法要求调用者传递对齐的数据,请使用未对齐的加载/存储

    您没有做任何事情来对齐源地址。您正在尝试在不更改存储地址的情况下对齐指针。您应该确保由
    temp
    指向的缓冲区正确对齐。此外,您还应该避免C++代码中的C样式转换。@ VTT:<代码>(μ-M128I*)< /C>是内部的标准样式。code>reinterpret\u cast(temp)通常过于庞大,英特尔的内部函数已经有足够长的名称了。(另外,
    \uuu m128i
    允许别名任何其他类型,因此它是特殊的。)如果您想要外观正常的asm输出,请不要在禁用优化的情况下编译。发射
    imul-edx,ecx,0
    是一种非常糟糕的归零方法
    edx
    。它正在执行
    movups
    加载,但随后溢出到堆栈上的临时位置并重新加载(使用对齐的加载),然后再次存储到它实际想要的结果。就像我说的,如果你希望ASM看起来像你在编写C++时所想象的那样,那么就可以启用优化。这里的悲哀部分是它不会崩溃到MSVC和ICC的新版本,因为它们通常会使用不对齐的访问。因此,与崩溃相反,您很难检测到性能问题。不幸的是,MSVC DEVS说这是设计的。如果你把它编译成C++,那就是C++。可以说它是用类似C的风格编写的,但这不会改变编译器对它的解释方式。C和C++之间有细微的差别。也许这个代码来自C示例,OP在C++中使用它。你也可以写代码“> > ASMASEAX,8 } /CODE,并在C++程序中编译它,但是这不构成汇编语言C++。我同意这一点,但仍然认为你应该用不同的方式来描述你的点1。如果你想批评C++风格中C风格的用法,当然可以。但这并不意味着C.Union类型双关语仍然是未定义的行为(除了我认为MSVC确实定义了它,和GNU C++一样)。但是你可以说,在某些方面,它确实使MSV++程序的ASM部分。MSVC内联asm与MASM的区别很小(例如,它接受
    0xdeadbeefh
    以及
    0deadbeefH