如何在C++内联汇编中实现数组负数求和?代码总返回0求排查
代码问题排查
你的代码始终返回0的核心原因及其他逻辑错误如下:
- 最致命错误:你
cmp ebx, 0比较的是数组的内存地址而非数组元素的值,用户态进程的数组地址永远是正数,所以永远触发jge bigger_case分支,总和自然一直是0。 - 地址计算逻辑完全混乱:你在列循环中反复修改基址寄存器
ebx,同时偏移esi的增量时机错误,导致访问的内存地址完全不是预期的数组元素位置。 - 分支跳转逻辑漏洞:负数分支读取元素时先偏移了
esi,读取的是下一个元素的值,累加逻辑完全错误。 - 寄存器保护缺失:Windows下内联汇编中
ebx属于被调用者保存寄存器,直接修改会破坏上层调用的上下文,需要先入栈保存,使用完后恢复。 - 行偏移计算逻辑不可靠:原代码行跳转逻辑依赖
esi的最终值,属于巧合可用的不稳定写法,应该直接按行字节大小计算跳转偏移。 - 注意:该语法仅支持32位MSVC编译器,64位MSVC已废弃内联汇编功能,需要单独编写汇编源文件实现。
修复后可运行代码
#include <iostream> using namespace std; void func(const int* arr, size_t arr_rows, size_t arr_cols, int* result) { int sum = 0; _asm { push ebx // 保存ebx寄存器,遵守调用约定 mov ebx, [arr] // 保存数组基址,后续不再随意修改 mov edx, 0 // 存储负数总和 mov ecx, [arr_rows] // 初始化行循环计数器 row_loop: push ecx // 暂存行循环计数器 xor esi, esi // 列索引从0开始 mov ecx, [arr_cols] // 初始化列循环计数器 col_loop: // 读取当前元素:基址 + 列索引*4(int占4字节) mov eax, dword ptr [ebx + esi*4] cmp eax, 0 // 比较元素值而非地址 jge next_col // 非负数直接跳过累加 add edx, eax // 负数累加到总和 next_col: inc esi // 列索引+1 loop col_loop // 列循环跳转 // 跳转至下一行起始地址 mov eax, [arr_cols] lea ebx, [ebx + eax*4] pop ecx // 恢复行循环计数器 loop row_loop // 行循环跳转 mov [sum], edx // 保存最终总和 pop ebx // 恢复ebx寄存器 } cout << sum << " is answer" << endl; *result = sum; // 给输出参数赋值 } // 测试用例 int main() { int arr[2][3] = {{-1, 2, -3}, {4, -5, 6}}; int res; func((const int*)arr, 2, 3, &res); // 预期输出:-9 is answer return 0; }
内容的提问来源于stack exchange,提问作者Elvin Jafarov
相关产品推荐
相关产品推荐

