4
  • 编译器:GCC 4.4.5(代码::块)
  • 平台:Linux 内核版本 2.6.32-5-686 (Debian)

我目前正在编写一个将字符串转换为 double long 的函数。我知道已经有一个功能可以做到这一点。我只是为了练习而编写这个函数,但我目前不知道该怎么做。

当我的函数只能处理正双长时,我的函数可以正常工作,因为如果它们是字符串中的无效字符,我可以返回 -1。但我希望该函数能够处理负双长以及正数。我不知道在这种情况下我应该做什么,因为现在所有实数都是有效的返回值。我考虑过通过将无效字符转换为十进制值或简单地忽略无效字符并仅选择有效字符 0-9(十进制 48-57)来继续转换,即使存在无效字符。我还考虑过返回一个指向 double long 的指针并使用 NULL 地址来指示找到了无效字符,或者我可以errno像函数一样设置readdir(). 我不确定我将如何进行设置errno,或者是否允许这样做。所以我的整体问题是你们会建议我在这种情况下做什么?另请注意,我尚未包含对负双长的处理,该函数将简单地忽略无效字符:例如$&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);

出于某些目的,如果您不一定要阅读所有字符串,那么了解消耗了多少字符串也可能很有用。在这种情况下,您可以返回 asize_tssize_t,以及 0(不消耗输入)或 -1 出错。然后,调用者可以检查输入字符串中的数字是否有任何意外。

errno在 C 中完全允许设置。

于 2013-04-27T14:24:43.643 回答
4

你有几个选择:

  1. 使用 NAN 作为错误值。请记住,您无法使用 . 检查 NAN ==。您必须使用isnan(x)orx!=x来检查是否x是 NAN。

  2. 添加一个附加int *errorp参数来存储是否发生错误的标志(可能还有错误代码)。此选项有两个子选项:您可能希望在成功时写入 0,或者您可能希望在成功时不理会先前的内容,以便调用者可以进行多次调用,并且只在最后检查其中是否有任何失败.

  3. 换个方式:传递一个指向结果存储位置的指针,并使用返回值作为错误代码。这种方法鼓励在每次调用后检查错误,但很难直接在表达式中使用结果,这可能很烦人。

  4. 通过特殊的线程本地状态报告错误:或者errno,浮点异常标志(警告:某些机器不支持 fenv/exceptions!),或者您自己的线程本地对象。根据您的观点,这可能是错误的/丑陋的,因为它是一个隐藏的信息通道,但它也可能对呼叫者最方便。

  5. 通过全局状态报告错误。请,永远不要这样做。它排除了对代码的多线程和干净库的使用。

于 2013-04-27T14:23:49.217 回答
2

errno可用于此。你需要#include <errno.h>为了使用它。您设置errno为一些预定义的值,然后调用者检查它:

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

请注意,这errno是线程安全的。如果您在一个线程中写入它,则该值在其他线程中不会更改。所以它不仅仅是一些全局变量。它甚至可以根本不是变量,而是内部编译器魔法。但关键是,您可以将其视为线程局部变量。

另一种方法是在额外的参数中传递错误:

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

我建议在错误时返回指向结果双精度或 NULL 的指针(如您所建议的那样),或者作为 strtoul() 添加指向第一个未转换字符的指针参数。

至于errno,它只是另一个全局变量(恰好在libc中声明),给它赋值就可以了。

于 2013-04-27T14:23:31.073 回答