汇编实现冒泡排序求助:现有代码未得到预期排序结果
冒泡排序汇编代码问题排查与修复
问题背景
尝试将C语言冒泡排序精确翻译成x86汇编,初始数组为{5,1,4,2,8},预期排序结果为{1,2,4,5,8},但现有代码无法得到正确结果,需排查并修正。
参考C语言冒泡排序代码
// C program for implementation of Bubble sort #include <stdio.h> int arr[] = { 5, 1, 4, 2, 8 }; void swap(int* xp, int* yp) { int temp = *xp; *xp = *yp; *yp = temp; } // A function to implement bubble sort void bubbleSort(int arr[], int n) { int i, j; for (i = 0; i < n - 1; i++) // Last i elements are already in place for (j = 0; j < n - i - 1; j++) if (arr[j] > arr[j + 1]) swap(&arr[j], &arr[j + 1]); } // Driver program to test above functions int main() { int n = sizeof(arr) / sizeof(arr[0]); bubbleSort(arr, n); return 0; }
现有汇编代码的核心错误
- elementswap函数逻辑完全错误:当前代码直接交换栈上的参数地址,而非地址指向的内存值,完全不符合swap函数的功能。
- bubblesort参数读取颠倒:C代码中
bubbleSort的参数顺序是(数组地址, n),对应汇编栈帧中[EBP+8]是数组地址、[EBP+12]是n,但现有代码搞反了两者,导致循环边界计算彻底错误。 - 内层循环数组指针未重置:每次进入innerloop时,edx未重置为当前轮次的数组起始位置,导致后续比较的元素位置混乱。
- swap调用参数传递错误:调用elementswap时未传入正确的相邻元素地址,而是错误压入寄存器值,不符合C代码中
swap(&arr[j], &arr[j+1])的参数要求。 - 循环边界计算错误:C代码中外层循环
i < n-1、内层循环j < n-i-1,现有汇编中sub ebx,2这类处理完全偏离逻辑,导致循环次数错误。
修正后的完整汇编代码
.386 .model flat, stdcall .stack 4096 ExitProcess proto, dwExitCode:dword .data myarr dd 5, 1, 4, 2, 8 ; 初始数组 .code elementswap proc push ebp mov ebp, esp push eax push ebx push ecx ; 读取参数: [EBP+8] = xp, [EBP+12] = yp mov eax, [ebp+8] ; eax = xp mov ebx, [ebp+12] ; ebx = yp mov ecx, [eax] ; ecx = *xp (temp) mov edx, [ebx] ; edx = *yp mov [eax], edx ; *xp = *yp mov [ebx], ecx ; *yp = temp pop ecx pop ebx pop eax mov esp, ebp pop ebp ret 8 ; 清理2个4字节参数,符合stdcall调用约定 elementswap endp bubblesort proc push ebp mov ebp, esp push esi push edi push edx push ebx mov esi, 0 ; i = 0 outerloop: mov ebx, [ebp+12] ; ebx = n sub ebx, 1 ; ebx = n-1 cmp esi, ebx ; 比较i和n-1 jge exit_outerloop ; i >= n-1时退出外层循环 mov edi, 0 ; j = 0 innerloop: mov ebx, [ebp+12] ; ebx = n sub ebx, esi ; ebx = n - i sub ebx, 1 ; ebx = n - i -1 cmp edi, ebx ; 比较j和n-i-1 jge exit_innerloop ; j >= n-i-1时退出内层循环 ; 计算arr[j]和arr[j+1]的地址 mov edx, [ebp+8] ; edx = arr起始地址 mov eax, edi shl eax, 2 ; eax = j*4 (int占4字节) add edx, eax ; edx = &arr[j] mov ecx, edx add ecx, 4 ; ecx = &arr[j+1] ; 比较arr[j]和arr[j+1] mov eax, [edx] cmp eax, [ecx] jle skip_swap ; arr[j] <= arr[j+1]则不交换 ; 调用swap函数 push ecx ; 第二个参数: &arr[j+1] push edx ; 第一个参数: &arr[j] call elementswap skip_swap: inc edi ; j++ jmp innerloop exit_innerloop: inc esi ; i++ jmp outerloop exit_outerloop: pop ebx pop edx pop edi pop esi mov esp, ebp pop ebp ret 8 ; 清理2个4字节参数,符合stdcall调用约定 bubblesort endp main proc push ebp mov ebp, esp ; 调用bubblesort(arr, n) mov eax, LENGTHOF myarr push eax ; 第二个参数: n push OFFSET myarr ; 第一个参数: arr地址 call bubblesort invoke ExitProcess, 0 main endp end main
关键修正说明
- elementswap函数修复:正确读取参数中的两个地址,交换地址指向的内存值,使用寄存器暂存临时值,同时通过
ret 8自动清理栈上的两个参数,符合stdcall调用约定。 - bubblesort参数修正:正确读取
[EBP+8]为数组地址,[EBP+12]为n值,严格按照C代码逻辑计算循环边界。 - 内层循环指针重置:每次进入innerloop时,重新计算当前j对应的数组元素地址,确保比较的是
arr[j]和arr[j+1]。 - swap参数正确传递:计算出两个相邻元素的地址,按顺序压栈后调用elementswap,完全匹配C代码的参数传递逻辑。
- 循环边界逻辑对齐:外层循环条件对应
i < n-1,内层循环条件对应j < n-i-1,保证循环次数正确。
内容的提问来源于stack exchange,提问作者Amalia
相关产品推荐
相关产品推荐

