【发布时间】: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