我正在编写一个x86汇编函数,用于确定字符串是否为回文序列(null终止符除外)。
如果字符串是回文,这个函数意味着返回0,如果字符串不是回文,它将返回失败的比较(即字符串左半部分的字符索引没有' t匹配)。
虽然它成功地检测了哪些字符串是否是回文,但它总是报告1
作为失败的回文测试的索引,无论它实际失败的位置。
汇编代码:
.386
.MODEL FLAT, C
.CODE
; Determines whether or not a given string is a palindrome
; Uses:
; ECX - pointer to start of string (incremented till halfway)
; EDX - pointer to end of string (decremented till halfway)
; AL - dereference character from ECX for comparison
; BL - dereference character from EDX for comparison
; ESI - index where comparison failed in case strings are not palindromes
; Arguments:
; [ESP+4] - pointer to string to test
; [ESP+8] - length of string
; Returns:
; 0 = string is a palindrome
; > 0 = string is not a palindrome; return value is the # comparison that failed (e.g. AABAAA would return 3)
; C prototype: int __cdecl palin(char *str, int len);
palin PROC
push ebx
push esi
; Load ECX with a pointer to the first character in the string
mov ecx, dword ptr [esp+12]
; Copy the pointer into EDX then add the length so EDX points to the end of the string
mov edx, ecx
add edx, dword ptr [esp+16]
xor esi, esi
loop0:
; Begin loop with decrement of EDX to skip the null terminator
dec edx
inc esi
mov al, byte ptr [ecx]
mov bl, byte ptr [edx]
cmp al, bl
; Comparison fail = strings cannot be palindromes
jnz not_palindrome
inc ecx
; If start ptr >= end ptr we are done, else keep looping
cmp ecx, edx
jl loop0
; Return 0 = success; string is a palindrome
xor eax, eax
jmp end_palin
not_palindrome:
; Return > 0 = fail; string is not a palindrome
mov eax, esi
end_palin:
pop esi
pop ebx
ret
palin ENDP
END
汇编函数的C驱动程序:
#include <stdio.h>
#include <string.h>
int __cdecl palin(char *str, int len);
int __cdecl main(int argc, char *argv[])
{
int ret;
if(argc<2)
{
printf("Usage: pal word");
return 0;
}
if(ret = (palin(argv[1], strlen(argv[1])) > 0))
{
printf("%s is not a palindrome; first comparison that failed was #%d\n", argv[1], ret);
}
else
{
printf("%s is a palindrome\n", argv[1]);
}
return 0;
}
示例输出:
C:\Temp>pal ABCDEEDCBA
ABCDEEDCBA is a palindrome
C:\Temp>pal ABCDEDCBA
ABCDEDCBA is a palindrome
C:\Temp>pal AABAAA
AABAAA is not a palindrome; first comparison that failed was #1
最后一行应该返回3而不是1 - 有谁知道这里发生了什么?
答案 0 :(得分:2)
您的代码中存在很少的错误......您正在寻找的是:
if(ret = (palin(argv[1], strlen(argv[1])) > 0))
这应该在好的C / C ++编译器中发出警告,我想,你在用什么?您是否使用-Wall -Wextra
(适用于gcc
或clang
,对于其他编译器,您应该查看它的文档。)
它正在执行ret = (res > 0)
,而(res&gt; 0)是布尔表达式,因此它是0
或1
。
你可能想要if ((ret = palin(argv[1], strlen(argv[1]))) > 0)
,这就说明为什么KISS有时会更好并将这些事情分成两行。
其他错误:
jl loop0
:应为jb
。 ecx
和edx
是内存指针,因此是无符号的。如果您的数据将在0x80000000边界上分配,那么jl
将首先失败cmp
。
您可以简化退出逻辑:
; Return 0 = success; string is a palindrome
xor esi, esi ; fake "esi" index = 0, reusing "not palindrome" exit code fully
not_palindrome:
; Return > 0 = fail; string is not a palindrome
mov eax, esi
pop esi
pop ebx
ret
最终风格挑剔:jnz not_palindrome
=&gt;我会为这个使用jne
别名,因为你要比较两个字符是否相等,而不是&#34;零&#34; (它是相同的指令,只是不同的别名,我倾向于使用两者,试图使用更合适的方式来遵循我的&#34;人类&#34;功能描述。)
此外,您可以执行cmp al,[edx]
而无需将第二个字符加载到bl
中(另外保存1条指令而不是ebx
,因此您不需要push/pop ebx
然后,再保存2个。)
如果您坚持将第二个字符加载到注册表中,那么“#34;易于阅读&#34;代码,你仍然可以使用ah
作为第二个字符,从代码中完全删除ebx
。