在 Linux 内核代码中使用 goto 没有意义

Pap*_*sha -1 c goto linux-kernel

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

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;
}
Run Code Online (Sandbox Code Playgroud)

我在 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;
}
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*lli 7

为什么函数不是这样重写的

您刚刚编写的函数无效。更准确地说,如果没有输入这个块:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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