文字列から整数への変換を行うアセンブリ言語のルーチンがあります。しかし、どうすれば失敗を返すことができますか?(たとえば、文字列に数字以外の文字が表示されます)整数値をゼロ以外の値に返します。通常のように、エラーとの変換をeax
区別できない理由はよくありません。たぶん失敗した場合は?どのように実装しますか?"0"
0
stc
3 に答える
これは、関数が従来の呼び出し規約に従う必要があるかどうかによって異なります。C関数など、アセンブリレベルで制御できない関数から呼び出すことができる場合は、コンパイラにチェックするように指示する方法がないため、キャリービットを使用してエラーを示すことはできません。また、コードが多くの場所で使用される場合は、すべての場所で値がどのように返されるかを知る必要があるため、呼び出し規約に従うのが最適な場合があります。
関数が制御可能なアセンブリコードによってのみ使用される場合は、必要に応じてエラーを返すことができます。キャリーフラグ(stc
)の設定は一般的な選択です。たとえば、BIOS機能で使用されており、個人的には以前に使用したことがあります。成功した場合は必ずキャリーフラグをクリアしてください(clc
)。
もう1つの可能性は、戻り値に2つのレジスタを使用することです。1つは実際の結果用で、もう1つはエラーコード用です。を使用する場合、これは実際には、64ビット整数または64ビットに収まる構造体の結果の場所としてedx
使用するgccなどの一部のコンパイラと互換性があります。edx:eax
最後に、すべてのコンパイラとの互換性を確保する必要がある場合は、関数に実際の結果へのポインタである追加の引数を取り、単にエラーコードを返すようにする必要があります。Cでは、これは次のようになります。
int myFunction(int otherArguments, int *resultPointer) {
int errorCode, result;
...
*resultPointer = result;
return errorCode;
}
簡単に言えば、1つの余分な値を返します。
オプション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;
}
オプション2、エラー変数へのポインターを渡します。
#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;
、返された構造をどこに格納するかがわかります。
これがアセンブリ内にあり、アセンブリによって呼び出されている場合は、あらゆる種類のオプションがあります。
%eax(%ebx、%ecxなど)以外のレジスタでエラーコード(エラーなしの場合は0、エラーの場合は1、またはエラーが発生した文字列のオフセット)を返すことができます。呼び出し元が保存することを確認してください。関数を呼び出す前にレジスタ)。
パリティ(PF)などのフラグを%eflagsに設定できます。RET命令はフラグを変更しないため、開始時にフラグをクリアして終了時に設定すると、ルーチンが戻ったときにフラグが設定されたままになります。クリアしてから設定するまでの間に変更されないフラグを選択してください。
例外(オーバーフローなど)をトリガーして、呼び出し元にキャッチさせることができますが、文字列変換などの場合、これは少し手間がかかります。例外が正しくキャッチされない場合、呼び出し元のアプリケーションがクラッシュする可能性があります。
アセンブリ言語ルーチンをライブラリ関数のように呼び出す(つまり、指定されていないプログラミング言語で確立された呼び出し規約を介して呼び出す)場合は、グローバルを使用するか、呼び出し元にパスを渡すという2つのオプションのいずれかがあります。ルーチンがエラーコードを書き込むために使用できるポインタ。strtoul(3)がどのようにそれを行うかを確認してください。