我有一个汇编语言例程,可以将字符串转换为整数。但是我怎么能返回失败呢?(例如,在字符串中看到非数字)它将整数值返回为eax
非零值,因为我通常这样做不是一个好主意,为什么我不能从错误"0"
转换为不同。0
也许stc
在失败的情况下?你如何实施它?
3 回答
如果这是在汇编中,被汇编调用,你有各种各样的选择。
您可以在 %eax 以外的寄存器中返回错误代码(0 表示没有错误,1 表示错误,或者发生错误的字符串中的偏移量)(%ebx,%ecx,随便什么——只要确保调用者保存在调用你的函数之前注册)。
您可以在 %eflags 中设置一个标志,例如奇偶校验 (PF)。RET 指令不修改任何标志,因此在进入时清除标志并在退出时设置它意味着当您的例程返回时标志仍然设置。确保选择在清除和设置之间不会被修改的标志!
您可以触发异常(例如溢出)并让调用者捕获它——但这对于字符串转换之类的东西来说有点笨拙。如果未正确捕获异常,您可能会导致调用应用程序崩溃。
如果您希望您的汇编语言例程像库函数一样被调用(即,通过未指定的编程语言中的既定调用约定调用),那么您确实有两个选择之一:使用全局,或者让调用者传入一个指针,您的例程可以用来向其写入错误代码。看看 strtoul(3) 是如何做到的。
简单地说,您返回一个额外的值。
选项一(在 C 中),使用全局变量:
#include <stdio.h>
int error = 0;
int String2Int(const char* s)
{
...
if (some_error_condition)
error = 1;
...
}
int main(void)
{
int value;
error = 0;
value = String2Int("12g");
if (error != 0)
printf("error!\n");
return 0;
}
选项二,传递一个指向错误变量的指针:
#include <stdio.h>
int String2Int(const char* s, int* error)
{
...
if (some_error_condition)
*error = 1;
...
}
int main(void)
{
int error = 0;
int value = String2Int("12g", &error);
if (error != 0)
printf("error!\n");
return 0;
}
选项树,返回一个结构:
#include <stdio.h>
struct valerr
{
int value;
int error;
};
struct valerr String2Int(const char* s)
{
struct valerr ve;
...
if (some_error_condition)
ve.error = 1;
...
return ve;
}
int main(void)
{
struct valerr ve = String2Int("12g");
if (ve.error != 0)
printf("error!\n");
return 0;
}
在后一种情况下,编译器可能会在 中插入一个隐式参数String2Int()
,指向ve
,以便return ve;
知道在哪里存储返回的结构。
这取决于您的函数是否需要遵循传统的调用约定。如果它可以被你没有汇编级控制的函数调用,例如 C 函数,那么你不能使用进位位来指示错误,因为没有办法告诉编译器检查它。如果您的代码将在许多地方使用,那么最好遵循调用约定,因为它们都需要知道它如何返回值。
如果您的函数仅由您可以控制的汇编代码使用,那么您可以根据需要返回错误。设置进位标志 ( stc
) 是一种常见的选择。比如BIOS功能用的,我个人以前也用过。只要确保在成功时清除进位标志 ( clc
)。
另一种可能性是使用两个寄存器作为返回值,一个用于实际结果,一个用于错误代码。如果使用edx
,这实际上与某些编译器兼容,例如 gcc,它edx:eax
用作 64 位整数或适合 64 位的结构的结果位置。
最后,如果你需要确保与所有编译器的兼容性,你应该让你的函数接受一个额外的参数,它是一个指向实际结果的指针,并简单地返回一个错误代码。在 C 中,这看起来像这样:
int myFunction(int otherArguments, int *resultPointer) {
int errorCode, result;
...
*resultPointer = result;
return errorCode;
}