2013-02-15 85 views
1

我有一个汇编语言的例程,可以将字符串转换为整数。但是,我怎么能返回失败? (例如,在字符串中看到一个非数字),它会将整数值返回到eax,非零值通常不是一个好主意,为什么我不能将"0"从错误转换为0。也许stc在失败的情况下?你如何实现它?从例程返回失败

回答

1

如果这是在装配中,被装配调用,你有各种选择。

您可以在%eax(%ebx,%ecx,无论 - 只是做出一个错误代码)的返回值中返回一个错误代码(0代表没有错误,1代表错误,或者错误发生的字符串中的偏移量)确保调用者在调用你的函数之前保存该寄存器)。

您可以在%eflags中设置一个标志,如奇偶校验(PF)。 RET指令不会修改任何标志,因此清除标志并将其设置为退出将意味着标志在您的例程返回时仍然置位。请确保选择一个在您清除并设置它之间不会修改的标志!

您可以触发一个异常(例如溢出)并让调用者捕获它 - 但这对于字符串转换等操作有点过分。如果未正确捕获异常,您可能会使调用应用程序崩溃。

如果您希望汇编语言例程像库函数那样被调用(即通过未指定的编程语言中已建立的调用约定调用),那么您确实有以下两种选择之一:使用全局函数或调用者传入一个你的例程可以用来写入错误代码的指针。看看strtoul(3)是如何做到的。

1

这取决于你的功能是否需要遵循传统的调用约定。如果它可以被你没有组装级别控制的功能调用,例如C函数,那么你不能使用进位位来指示错误,因为没有办法告诉编译器检查它。如果你的代码将在很多地方使用,那么最好遵循调用约定,因为它们都需要知道它是如何返回值的。

如果你的函数只被汇编代码使用,那么你可以根据需要返回一个错误。设置进位标志(stc)是常用选择。例如,BIOS功能使用它,我个人曾经使用它。请确保成功清除进位标志(clc)。

另一种可能性是使用两个寄存器作为返回值,一个用于实际结果,另一个用于错误代码。如果使用edx,这实际上与某些编译器(如gcc)兼容,后者使用edx:eax作为64位整数或适合64位的结构的结果位置。最后,如果您需要确保与所有编译器的兼容性,您应该让函数接受一个额外的参数,该参数是指向实际结果的指针,并且仅返回一个错误代码。在C中,这看起来像这样:

int myFunction(int otherArguments, int *resultPointer) { 
    int errorCode, result; 
    ... 
    *resultPointer = result; 
    return errorCode; 
} 
1

简而言之,您将返回一个额外的值。

选项之一(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;知道在哪里存储返回的结构。