【问题标题】:Use of goto in Linux kernel code makes no sense在 Linux 内核代码中使用 goto 没有意义
【发布时间】:2020-01-21 12:03:40
【问题描述】:

我正在浏览 Linux 源代码,here 我偶然发现了这个功能:

static int check_free_space(struct bsd_acct_struct *acct)
{
    struct kstatfs sbuf;

    if (time_is_after_jiffies(acct->needcheck))
        goto out;

    /* May block */
    if (vfs_statfs(&acct->file->f_path, &sbuf))
        goto out;

    if (acct->active) {
        u64 suspend = sbuf.f_blocks * SUSPEND;
        do_div(suspend, 100);
        if (sbuf.f_bavail <= suspend) {
            acct->active = 0;
            pr_info("Process accounting paused\n");
        }
    } else {
        u64 resume = sbuf.f_blocks * RESUME;
        do_div(resume, 100);
        if (sbuf.f_bavail >= resume) {
            acct->active = 1;
            pr_info("Process accounting resumed\n");
        }
    }

    acct->needcheck = jiffies + ACCT_TIMEOUT*HZ;
out:
    return acct->active;
}

我觉得 Marco 对 goto 的使用没有多大意义,尤其是因为它会导致 return 声明。为什么没有像这样重写函数:

static int check_free_space(struct bsd_acct_struct * acct) {
  struct kstatfs sbuf;

  if (time_is_after_jiffies(acct->needcheck) ||
    vfs_statfs( &acct->file->f_path, & sbuf)) {
    //latter may block
    return acct->active;
  }
  if (acct->active) {
    u64 suspend = sbuf.f_blocks * SUSPEND;
    do_div(suspend, 100);
    if (sbuf.f_bavail <= suspend) {
      acct->active = 0;
      pr_info("Process accounting paused\n");
    }
  } else {
    u64 resume = sbuf.f_blocks * RESUME;
    do_div(resume, 100);
    if (sbuf.f_bavail >= resume) {
      acct->active = 1;
      pr_info("Process accounting resumed\n");
    }
  }
  acct->needcheck = jiffies + ACCT_TIMEOUT * HZ;
}

我被告知goto 如果用于跳出嵌套循环或用于内存清理,确实很有用。这两种情况都不是这里的情况,那么为什么 Marco 选择gotos 呢?一定有什么正当理由吧?

【问题讨论】:

  • goto 在内核的很多地方都用到了。 could indeed be useful if used to break out of a nested loop - 这是对 goto 的错误使用。 As for the former, why? 因为这样很难正确地进行清理。如果每个循环都分配一些内存并获取一些资源,那就很难了。无论如何,内核编码指南允许 3 级缩进。 what alternatives - 一个函数。
  • 通常使用 goto 进行错误检查以避免过多的缩进级别。此外,内核例程需要一个用于 cleanip 的返回点。
  • @KamilCuk 至于前者,为什么?至于后者,有什么替代方案可以跳出嵌套循环?
  • 但是你使代码更丑陋,更难解析。在函数中有一个单一的入口和出口点几乎总是更好。在您的情况下,您根本不会在非错误情况下返回值。 goto 可以防止此类错误发生

标签: c linux-kernel goto


【解决方案1】:

为什么没有像这样重写函数

你刚才写的函数无效。更准确地说,如果没有进入这个块:

if (time_is_after_jiffies(acct->needcheck) ||
  vfs_statfs( &acct->file->f_path, & sbuf)) {
    vfs_statfs( &acct->file->f_path, & sbuf)) {
    //latter may block
    return acct->active;
}

那么该函数将无法在其他任何地方执行有效的return。代码甚至无法编译。

goto 在该特定函数中的目的是执行提前返回,而无需复制return acct-&gt;active; 行。这是一种非常常见的模式,可以节省重复的代码行,有时还可以减小生成的可执行文件的大小。

【讨论】:

    【解决方案2】:

    这是“单一回报”原则。一些程序员认为应该始终遵守它。

    如果您将goto out; 替换为return acct-&gt;active;,则该函数的工作方式完全相同

    这里有一个关于单次退货的问题:Should a function have only one return statement?

    【讨论】:

      猜你喜欢
      • 2011-02-02
      • 2018-01-14
      • 2012-02-08
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多