4
  • コンパイラ: GCC 4.4.5 (コード::ブロック)
  • プラットフォーム: Linux カーネル バージョン 2.6.32-5-686 (Debian)

現在、文字列を double long に変換する関数を作成しています。これを行う機能がすでにあることは承知しています。練習のためにこの関数を書いているだけですが、現在何をすべきかわかりません。

私の関数は、正の double long のみを処理できる場合に正しく機能しました。これは、文字列内の無効な文字である場合に -1 を返す可能性があるためです。しかし、私は関数が正と同様に負の double long を処理できるようにしたいと考えています。現在、すべての実数が有効な戻り値であるため、この状況で何をすべきかわかりません。無効な文字を 10 進値に変換するか、単に無効な文字を無視して有効な文字 0 ~ 9 (10 進数 48 ~ 57) のみを選択することにより、無効な文字が存在しても変換を続行することを考えました。errnoまた、double long へのポインターを返し、無効な文字が見つかったことを示すために NULL アドレスを使用するか、関数のように設定することも考えました。readdir(). どのように設定するのerrnoか、またはそれが許可されているかどうかはわかりません。それで、私の質問は全体として、この状況で私が何をすることをお勧めしますか? また、負の double long の処理はまだ含めていないことに注意してください。関数は単に無効な文字を無視します。たとえば$&3%7AJ89、3789 に変換されます。

double long cstrtodl(const char *cstr)
{
double long power;
double long dl = 0;
int decimal_place;
int bool_decimal = 0;

for(decimal_place = 1; cstr[decimal_place] != '\0'; decimal_place++)
{
    if(cstr[decimal_place] == '.')
    {
        bool_decimal = decimal_place;
        break;
    }
}

for(decimal_place--, power = 1; decimal_place >= 0; decimal_place--, power *= 10)
{
    printf("[%i] = %i(%c)\nPOWER = %LF\nINTEGER = %LF\n", decimal_place, (int)cstr[decimal_place], cstr[decimal_place], power, dl);
    switch(cstr[decimal_place])
    {
        case 48:
            dl += 0 * power;
        break;

        case 49:
            dl += 1 * power;
        break;

        case 50:
            dl += 2 * power;
        break;

        case 51:
            dl += 3 * power;
        break;

        case 52:
            dl += 4 * power;
        break;

        case 53:
            dl += 5 * power;
        break;

        case 54:
            dl += 6 * power;
        break;

        case 55:
            dl += 7 * power;
        break;

        case 56:
            dl += 8 * power;
        break;

        case 57:
            dl += 9 * power;
        break;

        default:
            power /= 10;
        break;
    }
}

if(bool_decimal > 0)
{
    for(decimal_place = bool_decimal+1, power = 10; cstr[decimal_place] != '\0'; decimal_place++, power *= 10)
    {
        printf("[%i] = %i(%c)\nPOWER = %LF\nINTEGER = %LF\n", decimal_place, (int)cstr[decimal_place], cstr[decimal_place], power, dl);
        switch(cstr[decimal_place])
        {
            case 48:
                dl += 0 / power;
            break;

            case 49:
                dl += 1 / power;
            break;

            case 50:
                dl += 2 / power;
            break;

            case 51:
                dl += 3 / power;
            break;

            case 52:
                dl += 4 / power;
            break;

            case 53:
                dl += 5 / power;
            break;

            case 54:
                dl += 6 / power;
            break;

            case 55:
                dl += 7 / power;
            break;

            case 56:
                dl += 8 / power;
            break;

            case 57:
                dl += 9 / power;
            break;

            default:
                power /= 10;
            break;
        }
    }
}

return dl;
}
4

4 に答える 4

5

ポインターを返すことは複雑で非効率的です。mallocバッファーを取得してから覚えておく必要がfreeあるからです。これは、単純な固定サイズの値を返すための大きなオーバーヘッドです。代わりに、ステータス コードを返し、結果をポインターに書き込むことができます。

// returns zero on success, -1 on error
int cstrtodl(const char *cstr, long double *result);

一部の目的では、必ずしもすべてを読み取る必要がない場合に、文字列がどれだけ消費されたかを知ることも役立つ場合があります。その場合、size_tまたはを返すことができ、ssize_tエラーの場合は 0 (入力が消費されない) または -1 のいずれかを返します。呼び出し元は、入力文字列の数字の後に予期しないものが続くかどうかを確認できます。

Cでは設定errnoが完全​​に許可されています。

于 2013-04-27T14:24:43.643 に答える
4

いくつかのオプションがあります:

  1. NAN をエラー値として使用します。では NAN をチェックできないことに注意してください==。がNANかどうかを確認するには、isnan(x)またはを使用する必要があります。x!=xx

  2. int *errorpエラーが発生したかどうかのフラグ (および場合によってはエラー コード) を格納するための追加の引数を追加します。このオプションには 2 つのサブオプションがあります。成功した場合は 0 を書き込むか、成功した場合は前の内容をそのままにして、発信者が複数の呼び出しを行い、最後に失敗したかどうかのみを確認できるようにすることができます。 .

  3. 物事を切り替える: 結果を格納する場所へのポインターを渡し、エラー コードの戻り値を使用します。このアプローチでは、呼び出しのたびにエラーをチェックすることが奨励されますが、結果を式で直接使用することが難しくなり、煩わしい場合があります。

  4. 特殊なスレッドローカル状態を通じてエラーを報告します:errno浮動小数点例外フラグ (警告: 一部のマシンは fenv/例外をサポートしていません!)、または独自のスレッドローカル オブジェクトのいずれかです。視点によっては、これは隠された情報チャネルであるため、間違っているか醜いかもしれませんが、発信者にとって最も便利な場合もあります。

  5. グローバル状態を通じてエラーを報告します。絶対にしないでください。コードのマルチスレッドでクリーンなライブラリの使用が妨げられます。

于 2013-04-27T14:23:49.217 に答える
2

errnoこれに使用できます。使用するために必要です#include <errno.h>。定義済みの値に設定errnoすると、呼び出し元がそれをチェックします。

errno = 0;
cstrtodl(some_string);
if (errno != 0) {
    // Error occured.
}

errnoスレッドセーフであることに注意してください。あるスレッドで書き込んだ場合、値は他のスレッドでは変更されません。したがって、単なるグローバル変数ではありません。まったく変数ではなく、内部コンパイラの魔法である場合もあります。しかし要点は、それをスレッドローカル変数であるかのように扱うことができるということです。

もう 1 つの方法は、追加の引数でエラーを渡すことです。

double long cstrtodl(const char *cstr, int *error)
{
    // ...
    if (error != NULL) {
        if (some_error_occured) {
            *error = SOME_CONSTANT_OR_MACRO;
        } else {
            *error = 0;
        }
    }
}

呼び出し元は、次のことができます。

int error;
cstrtodl(some_string, &error);
if (*error) {
    // Error occured.
}

または、発信者が関心がない場合:

cstrtodl(some_string, NULL);
于 2013-04-27T14:24:11.883 に答える
1

エラー時に結果の double または NULL へのポインターを返すか (提案したように)、strtoul() として、変換されていない最初の文字を指すポインター パラメーターを追加することをお勧めします。

errno に関しては、これは単なる別のグローバル変数 (たまたま libc 内で宣言されている) であり、それに独自の値を割り当てても問題ありません。

于 2013-04-27T14:23:31.073 に答える