4
int fcntl(int fd, int command, ... /* arg */ );

它是否可移植:(flags = fcntl(fd, F_GETFL);注意:否arg)?

Linux和FreeBSD手册页都说它arg被忽略了:

F_GETFL (void)
    Get the file access mode and the file status flags; arg
    is ignored.

void在 Linux 文档中意味着这arg不是必需的。

这是来自 POSIX 的相关标志的用法示例F_GETFD

#include <unistd.h>
#include <fcntl.h>
...
    int flags;


    flags = fcntl(fd, F_GETFD);
    if (flags == -1)
        /* Handle error */;
    flags |= FD_CLOEXEC;
    if (fcntl(fd, F_SETFD, flags) == -1)
        /* Handle error */;"

它表明(今天)arg不需要。F_GETFD然后它说:

F_GETFD、F_SETFD、F_GETFL 和 F_SETFL 的 arg 值都表示允许未来增长的标志值。

这是否意味着将来F_GETFL可能会使用?arg

在 Ohloh 代码上快速搜索“F_GETFL”会产生大多数开源项目确实通过arg的印象(通常0,有时NULL,甚至(损坏?)&fl)。我不明白为什么fcntl(fd, F_GETFL, 0)是首选形式。@Wumpus Q. Wumbley 认为这可能是由也使用表单的“UNIX 环境中的高级编程”一书引起的。fcntl(fd, F_GETFL, 0)

是否有需要第三个参数的系统/编译器:flags = fcntl(fd, F_GETFL, 0);?今天或将来是否可以fcntl(fd, F_GETFL)产生fcntl(fd, F_GETFL, 0)不同的结果(假设一个合规的实施)?

4

3 回答 3

5

查看 fcntl 命令的其余部分。请注意其中一些(F_DUPFD、F_SETFL 和其他)如何告诉您第三个参数的用途。使用其中一个参数时,您需要提供第三个参数。使用 F_GETFL 或 F_GETFD 时不会。

在 SYNOPSIS 中,您可以看到 fcntl 需要 2 个 args 加上 a...这意味着第三个 arg 在不使用时可以省略。

在做了更多的研究之后,我发现有一些旧的手册页(大约从第一个 APUE 开始),其中 SYNOPSIS 暗示所有 3 个参数都是必需的。示例:http ://www.freebsd.org/cgi/man.cgi?query=fcntl&manpath=FreeBSD+2.2.7-RELEASE

SYNOPSIS
     #include <fcntl.h>

     int
     fcntl(int fd, int cmd, int arg);

我找不到任何证据表明它实际上是在标头中以这种方式声明的,但如果是这样,那么当仅使用 2 个参数调用它时编译将失败。这将是在代码中包含额外的 0 参数的一个很好的理由。

如果我的猜测是正确的,并且这是历史上使用 3-arg F_GETFL 的实际原因,那么在函数原型是新的和可怕的并且 OS 供应商弄错了它们的时候,它就是一个无用的化石。

于 2014-07-31T14:52:01.210 回答
2

这两个调用

flags = fcntl(fd, F_GETFL);
flags = fcntl(fd, F_GETFL, 0);

是等价的,因为第三个可变参数被忽略了。如果您查看fs/fcntl.c:262fs/fcntl.c:269,您会发现arg没有使用。
但是,当您需要设置某个值时,您应该传递您要设置的值。
您可以将其视为fcntlgetter 和 setter 的 OOP 等价物。

是否存在需要第三个参数的系统:flags = fcntl(fd, F_GETFL, 0);?

我不知道。至少 Linux 没有。该文档明确指出它被忽略了,因为不会使用arg. 您可以通过某些东西的事实并不意味着您必须这样做。

是否可以 在某些系统fcntl(fd, F_GETFL)fcntl(fd, F_GETFL, 0)返回不同的结果(过去、今天和将来(假设一致的实现))?

lxr允许我们深入研究旧版本的 Linux,甚至在 1991 年的 Linux 2.0.4 中,忽略fcntl了第三个参数。接受任何进一步的论点是没有意义的。因此,如果存在第三个参数有意义的系统,那么它肯定不是 Linux。


我做了一些进一步的研究,发现了一些相互矛盾的结果。看这里:有一些书(我没有发布它们可能的直接链接protected)确实建议fcntl作为三参数函数。但是,至少关于GETFL/ GETFD,没有提及arg
恕我直言,它的行为从未被认真对待:也就是说,是什么让你想知道。此外,我什至认为使用第三个论点是有害的:如果它确实/将有意义怎么办?

我再次通过 Linux,这些命令的第三个参数从未通过。

最后

是否有需要第三个参数的系统/编译器:flags = fcntl(fd, F_GETFL, 0);?fcntl(fd, F_GETFL) 和 fcntl(fd, F_GETFL, 0) 能否在今天或将来产生不同的结果(假设实现兼容)?

未来是个谜。今天我有足够的把握将其排除在外。然而,在过去可能是这样的。

于 2014-07-31T14:59:08.540 回答
2

在 FreeBSD 基本系统中,fcntl(fd, F_GETFL)fcntl(fd, F_GETFL, 0)都被使用。但在大多数情况下,使用第三个参数 0。这可能是由于历史原因,因为fcntl可以追溯到 4.2BSD,并通过 4.4BSD-Lite 源代码导入 FreeBSD。

在 4.4BSD(和 FreeBSD 2.0)中,手册页将参数列为强制: int fcntl(int fd, int cmd, int arg),即使实际的老式标头没有: int fcntl(int, int, ...)

至于为什么,那就很难回答了。我们必须询问原作者。但是由于原始源代码管理标签中没有记录(用户)名称,我不知道如何跟踪它们。

额外的 0 参数可能从未在 FreeBSD 代码库中删除,因为它不会破坏任何东西,因此对于“修复”来说不够重要。

于 2014-08-05T10:44:13.303 回答