VS内嵌汇编实现集合差运算时遭遇读访问违例问题求助
问题根源与修复方案
核心错误分析
非法指针起始位置
int* ptr1 = arr1.data() - 1;和int* ptr2 = arr2.data() - 1;直接指向vector缓冲区的前一个内存地址,属于未定义行为,后续指针偏移操作极易触发内存访问越界。_delete分支的致命逻辑错误
在_delete标签下执行loop _array2完全违背预期:loop指令依赖ecx寄存器的计数,此时ecx是arr1剩余的遍历次数,跳转到_array2会导致指针、计数器彻底混乱,直接引发读访问违例,这就是你看到ptr1变成0xFFFFFFD7(-41的补码,明显越界的指针值)的原因。未正确统计删除次数与更新vector状态
numberOfDeletes全程未递增,且手动修改内存后未调用vector的resize()或erase()来更新内部的size和缓冲区状态,导致vector的内部数据与实际内存状态不匹配。元素删除的逻辑漏洞
当前删除逻辑仅用下一个元素覆盖当前元素,未完成后续所有元素的前移操作,无法真正实现元素删除。
修正后的代码
以下是修复了上述问题的实现,同时保留内嵌汇编的逻辑:
#include <vector> using namespace std; int main() { vector<int> arr1 = {8, 3}; vector<int> arr2 = {7, 8}; int* ptr1 = arr1.data(); // 直接指向vector的起始地址 int size1 = arr1.size(); int* ptr2 = arr2.data(); int size2 = arr2.size(); int numberOfDeletes = 0; __asm { mov ebx, ptr2 mov edx, 0 ; arr2的遍历索引 _array2: cmp edx, size2 je _out ; 遍历完arr2就退出 mov esi, dword ptr[ebx] ; 取出arr2当前元素 mov eax, ptr1 mov ecx, size1 sub ecx, numberOfDeletes ; 排除已删除的元素,实际遍历长度 _comparing: cmp dword ptr[eax], esi je _delete ; 找到匹配元素,执行删除 add eax, 4 loop _comparing ; 没找到匹配,移动到arr2下一个元素 add ebx, 4 inc edx jmp _array2 _delete: ; 从当前位置开始,将后续元素依次前移 mov edi, eax _shift_elements: mov ebp, dword ptr[edi + 4] mov dword ptr[edi], ebp add edi, 4 cmp edi, ptr1 + (size1 - numberOfDeletes) * 4 jl _shift_elements inc numberOfDeletes ; 统计删除次数 ; 删除后,继续检查当前位置(因为前移后的元素可能也匹配) jmp _comparing _out: ; 更新vector的实际大小 mov size1, size1 - numberOfDeletes } ; 让vector同步内部状态 arr1.resize(size1); return 0; }
额外注意事项
- 不要直接操作vector的原始指针并修改内存,除非你非常清楚vector的内存布局;优先使用vector提供的
erase()、remove()等成员函数,安全性和可维护性更高。 - 内嵌汇编在现代C++中属于不推荐的写法,尤其是在64位环境下兼容性极差;如果必须使用汇编,建议单独写成函数而非内嵌。
内容的提问来源于stack exchange,提问作者Ruslan Vaitukevich
相关产品推荐
相关产品推荐

