【问题标题】:What's the right way to handle this error checking?处理此错误检查的正确方法是什么?
【发布时间】:2011-07-11 03:05:36
【问题描述】:

我有一个函数应该传递一个带有两个数字的字符串(作为正则表达式:/-?[0-9]+ -?[0-9]+/)并返回第二个。

我决定程序应该进行错误检查。首先,它应该测试字符串是否实际上是所需的形式;其次,它应该确保第一个数字(返回的)是连续的。

现在我已经编程了很长时间,这不是一项艰巨的任务。 (由于数字不需要适合机器词,这使得它稍微困难一些。)但我的问题是我应该如何 这样做,而不是我如何可以 .我提出的所有解决方案都有些难看。

  • 我可以使用一个全局变量来保存这些值并比较它们(或者如果它是NULL,则将值保留在那里);这似乎是错误的事情。
  • 我可以通过引用传递一个或两个返回值和最后/当前行的第一个数字并修改它们
  • 我可以使用返回值来给出一个布尔值,因为有/没有错误

因此,任何与在 C 中处理此类错误检查的正确方法有关的任何想法都将受到欢迎。


这与更理论化的question I asked on cstheory 有关。供参考,这里是函数:

char*
scanInput(char* line)
{
    int start = 0;
    while (line[start] == ' ' || line[start] == '\t')
        start++;
    if (line[start] == '#')
        return NULL;    // Comment
    if (line[start] == '-')
        start++;
    while (line[start] >= '0' && line[start] <= '9')
        start++;
    while (line[start] == ' ' || line[start] == '\t')
        start++;
    int end = start;
    if (line[end] == '-')
        end++;
    while (line[end] >= '0' && line[end] <= '9')
        end++;
    if (start == end)
        return NULL;    // Blank line, or no numbers found
    line[end] = '\0';

    return line + start;
}

它是这样调用的:

while(fgets(line, MAX_LINELEN, f) != NULL) {
    if (strlen(line) > MAX_LINELEN - 5)
        throw_error(talker, "Maximum line length exceeded; file probably not valid");
    char* kept = scanInput(line);
    if (kept == NULL)
        continue;
    BIGNUM value = strtobignum(kept);
    if (++i > MAX_VECLEN) {
        warning("only %d terms used; file has unread terms", MAX_VECLEN);
        break;
    }
    // values are used here
}

【问题讨论】:

    标签: c error-handling validation


    【解决方案1】:

    C 中的传统解决方案是使用按引用传递(指针)来返回函数计算的值并使用返回值进行错误处理,就像 scanf 的做法一样。

    int scanInput(char **line_p int *number){
        char * line = *line_p;
        ...
        if(something bad happens){
            return 1;
        }
        ...
        *linep = line + start;
        *number = ...;
        return 0; //success
    }
    
    int main(){
        char word[100]; strcpy(word, "10 17");
        char *line = word;
        int number;
        switch(scanInput(&line, &number)){
            case 1:
            default:
        }
    }
    

    加分:

    • 使用一些枚举来为错误代码赋予含义可能是个好主意。
    • 如果您可以使用 C++(或类似)异常通常是错误处理的最佳解决方案,因为您不必再​​用 if 填充代码
    • 全局变量通常是邪恶的。如果您想使用它们,请考虑将您需要的状态封装在一个结构中并传递一个指向它的指针。在 OO 意义上,将其视为“this”指针。

    【讨论】:

      【解决方案2】:

      最终,您将需要隔离并转换每行中的两个大数字。要检查该行上的第一个数字是否是前一个数字,您必须记录最后找到的此类数字。因此,您可能需要如下结构:

      BIGNUM old_value = 0;  // See notes below
      
      while (fgets(line, sizeof(line), f) != 0)
      {
          BIGNUM value1;
          BIGNUM value2;
          if (ScanDoubleBigNum(line, &value1, &value2) != 0)
              ...handle line format error...
          if (old_value == 0 || are_consecutive(old_value, value1))
          {
              // OK - valid information found
              // Release old_value
              old_value = value1;
              process(value2);
              // Release value2
          }
          else
              ...handle non-consecutive error...
      }
      

      are_consecutive() 函数确定它的第二个参数是否比第一个大一个。 process() 函数可以对第二个值做任何你需要做的事情。 ScanDoubleBigNum() 函数与您的 ScanInput() 相关,但它读取两个值。实际代码将调用另一个函数(称为 ScanBigNum()),其中包含大约一半的 ScanInput()(因为它包含两次基本相同的代码),以及当前在循环中发生的转换。 ScanDoubleBigNum() 中的代码将调用 ScanBigNum() 两次。请注意,ScanBigNum() 需要确定扫描完成的位置,以便第二次调用可以在第一次停止的地方继续。

      我冒昧地假设BIGNUM 是一个由指针标识的已分配结构,因此初始化BIGNUM old_value = 0; 是一种表示还没有值的方式。大概有一个函数可以释放BIGNUM。如果这是不正确的,那么您需要调整建议的代码以适应 BIGNUM 类型的实际行为。 (这是基于 OpenSSL 还是 SSLeay 代码?)

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-02
      • 2017-09-20
      • 2021-12-16
      • 2018-09-21
      • 2011-12-26
      相关资源
      最近更新 更多