NASM汇编实现5个不同长度字符串字符交错拼接求助
适配不同长度字符串的NASM交错提取实现与优化方案
核心问题分析
现有代码仅计算第一个字符串的长度并以此作为循环次数,未考虑其他字符串长度可能更短或更长的情况,导致短字符串会被读取到换行符或垃圾数据,长字符串的后续字符无法被提取。要实现不同长度字符串的交错提取,核心是为每个字符串单独记录长度,并在提取字符时判断当前索引是否在字符串的有效范围内。
优化实现思路
- 为每个字符串单独计算并存储长度,避免依赖单一字符串的长度
- 使用数组存储所有字符串的地址和对应长度,通过循环统一处理,消除冗余代码
- 先确定所有字符串中的最大长度,以此作为外层循环的次数,确保所有字符串的有效字符都被提取
- 每次提取字符前检查当前索引是否小于对应字符串的长度,仅提取有效范围内的字符
优化后的NASM代码
segment .data instruccion db 'Ingrese 5 cadenas (cada una no mayor a 20 caracteres):',0x0A lonI EQU ($-instruccion) segment .bss ; 输入字符串缓冲区(多留1字节存换行符) cad1 resb 21 cad2 resb 21 cad3 resb 21 cad4 resb 21 cad5 resb 21 ; 存储字符串地址与长度的数组 str_ptrs resd 5 ; 每个元素存字符串起始地址(双字) str_lens resd 5 ; 每个元素存字符串有效长度(不含换行符,双字) output resb 101 ; 输出缓冲区,最多容纳5*20+1=101字节 segment .text global _start _start: ; 打印提示信息 mov edx, lonI mov ecx, instruccion call imprimir ; 读取5个字符串,记录地址与有效长度 mov dword [str_ptrs], cad1 mov ecx, cad1 call leer call calc_len mov dword [str_lens], eax mov dword [str_ptrs+4], cad2 mov ecx, cad2 call leer call calc_len mov dword [str_lens+4], eax mov dword [str_ptrs+8], cad3 mov ecx, cad3 call leer call calc_len mov dword [str_lens+8], eax mov dword [str_ptrs+12], cad4 mov ecx, cad4 call leer call calc_len mov dword [str_lens+12], eax mov dword [str_ptrs+16], cad5 mov ecx, cad5 call leer call calc_len mov dword [str_lens+16], eax ; 找出最长字符串的长度,作为外层循环次数 mov esi, str_lens mov ecx, 5 mov eax, 0 find_max_len: cmp eax, [esi] jge skip_update mov eax, [esi] skip_update: add esi, 4 loop find_max_len mov ebx, eax ; ebx存储最大长度 ; 交错提取字符到输出缓冲区 mov edi, output mov ecx, 0 ; ecx为当前字符索引i outer_loop: cmp ecx, ebx jge end_outer_loop ; 遍历5个字符串,尝试提取第i个字符 mov esi, str_ptrs mov edx, 5 inner_loop: mov eax, [esi + 4*(edx-1)] ; 获取当前字符串地址 mov ebp, [str_lens + 4*(edx-1)] ; 获取当前字符串长度 cmp ecx, ebp jge skip_char ; 索引超出长度,跳过提取 ; 复制字符到输出缓冲区 mov al, [eax + ecx] stosb skip_char: dec edx jnz inner_loop inc ecx jmp outer_loop end_outer_loop: ; 添加换行符 mov al, 0x0A stosb ; 打印结果 mov edx, edi - output ; 计算输出字符串实际长度 mov ecx, output call imprimir ; 退出程序 mov eax, 1 int 0x80 ; 子函数:读取字符串,ecx=缓冲区地址,edx=最大读取字节数 leer: mov edx, 21 mov ebx, 0 mov eax, 3 int 0x80 ret ; 子函数:计算字符串有效长度,ecx=缓冲区地址,返回eax=有效长度(不含换行符) calc_len: mov edi, ecx mov eax, 0x0A mov ecx, 21 repne scasb dec edi ; 回到换行符位置 mov eax, edi - ecx ; 有效长度=换行符位置 - 起始地址 ret ; 子函数:打印字符串,ecx=字符串地址,edx=长度 imprimir: mov ebx, 1 mov eax, 4 int 0x80 ret
关键细节说明
- 字符串长度计算:
calc_len子函数通过repne scasb定位换行符,用换行符地址减去字符串起始地址,得到不含换行符的有效长度,确保每个字符串的实际长度被准确记录。 - 最大长度获取:遍历长度数组找到最长字符串的长度,以此作为外层循环次数,保证所有字符串的有效字符都能被处理。
- 边界检查:内层循环处理每个字符串时,先判断当前索引是否小于该字符串的长度,仅在有效范围内才提取字符,避免读取无效内存。
- 代码复用:通过字符串地址数组和长度数组,用循环统一处理5个字符串,消除了原代码中重复的处理逻辑,提升了代码可维护性。
内容的提问来源于stack exchange,提问作者Emilio Díaz
相关产品推荐
相关产品推荐

