在使用 DirectX 12.0 进行编程时,我偶然发现了一个相当不寻常的问题。到目前为止,还没有任何研究具有洞察力。
我正在使用 C(不是 C++)进行编程。看起来官方的 DirectX 12 标头支持 C 和 C++ 的绑定,但是编写 C 等效代码来执行上述任务会导致崩溃,而 C++ 则不会。我不相信错误是我的。
以下是详细信息:我的 D3D12 设备初始化过程中有以下代码块:
/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = pThis->pRTVHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(pThis->pRTVHeap);
其中hRTV代表“渲染目标视图的句柄”(D3D12_CPU_DESCRIPTOR_HANDLE),而pRTVHeap代表“指向渲染目标视图堆的指针” (ID3D12DescriptorHeap)。
这是 C++ 等价物 - 这很好用:
/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = this->pRTVHeap->GetCPUDescriptorHandleForHeapStart();
不存在编译时错误,但在运行时,在 C 中调用此方法 (GetCPUDescriptorHandleForHeapStart) 会触发堆栈损坏(%ESP 被替换 4 个字节)。
我检查了该方法的反汇编并记下了 RET(返回)指令:
mov edi,edi
push ebp
mov ebp,esp
mov ecx,dword ptr [ebp+8]
mov eax,dword ptr [ecx+2Ch]
cmp dword ptr [eax],2
jne 5029004A
mov eax,dword ptr [ebp+0Ch]
mov ecx,dword ptr [ecx+28h]
mov dword ptr [eax],ecx
jmp 50290055
push dword ptr [ebp+0Ch]
call 5029005E
mov eax,dword ptr [ebp+0Ch]
pop ebp
ret 8
对于那些熟悉汇编和(希望)__stdcall
COM(组件对象模型)对象的调用约定的人this
来说,在堆栈上传递的(或等效的)指针是第一个参数(在这种情况下,应该是唯一的参数)的方法,一种使 COM 对象能够访问自己的数据的做法。
以下代码片段(也显示在上面)引起了我的困惑,当运行时抛出“未对齐的堆栈指针/堆栈损坏”(%ESP)错误时,这是理所当然的:
ret 8
在这种情况下,只应传递一个参数(this
指针)。指针的大小(在 32 位系统上——我的目标架构是 x86)是 4 个字节(32 位),那么为什么被调用者清理堆栈上的 8 个字节呢?
我称这为错误是否正确?Microsoft 是否需要被告知此问题?我错了吗?
感谢您抽出宝贵的时间,希望比我有更多知识的人能启发我。请不要提出偏爱 C++ 而不是 C 的古老论点。