когда требуется аргумент для команды F_GETFL fcntl?

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 (сегодня). Затем он говорит:

Значения arg для F_GETFD, F_SETFD, F_GETFL и F_SETFL представляют собой значения флагов для обеспечения возможности расширения в будущем.

Означает ли это, что F_GETFL может использовать arg в будущем?

Быстрый поиск "F_GETFL" в коде Ohloh создает впечатление, что большинство проектов с открытым исходным кодом проходят arg (обычно 0, иногда NULL или даже (неверно?) &fl). Я не понимаю, почему fcntl(fd, F_GETFL, 0) предпочтительнее. @Wumpus Q. Wumbley предлагает что это может быть вызвано книга "Advanced Programming in the UNIX Environment", в которой также используется форма fcntl(fd, F_GETFL, 0).

Есть ли система/компилятор, для которого требуется третий аргумент: flags = fcntl(fd, F_GETFL, 0);? Могут ли fcntl(fd, F_GETFL) и fcntl(fd, F_GETFL, 0) давать разные результаты сегодня или в будущем (при соответствующей реализации)?


person jfs    schedule 31.07.2014    source источник
comment
@mafso: могу ли я использовать flags = fcntl(fd, F_GETFL);? Или вместо этого следует использовать flags = fcntl(fd, F_GETFL, 0);, например, для переносимости? Примечание: POSIX показывает пример для F_GETFD, но я спрашиваю о F_GETFL.   -  person jfs    schedule 31.07.2014
comment
В базовой системе FreeBSD используются обе формы. Но в большинстве случаев используется третий аргумент 0 . Но это может быть по историческим причинам, поскольку fcntl восходит к 4.2BSD.   -  person Roland Smith    schedule 04.08.2014
comment
@RolandSmith: это похоже на пример культового программирования: 0 используется APUE как указал @Wumpus Q. Wumbley, и поэтому люди могут копировать код, не понимая его (я не вижу никаких указаний на то, что 0 необходим в любой системе/компиляторе).   -  person jfs    schedule 05.08.2014
comment
@J.F.Sebastian J.F.Sebastian Или, возможно, разработчики считают это слишком тривиальным, чтобы тратить усилия на его удаление из кодовой базы.   -  person Roland Smith    schedule 05.08.2014
comment
@RolandSmith: как вы вообще объясните появление 0 в кодовой базе?   -  person jfs    schedule 05.08.2014
comment
@JFSebastian Наследие 4.4BSD, где на странице руководства указан аргумент как обязательно, даже если фактический заголовок нет.   -  person Roland Smith    schedule 05.08.2014
comment
@RolandSmith: Не могли бы вы добавить это в качестве ответа?   -  person jfs    schedule 05.08.2014


Ответы (3)


Посмотрите на остальные команды fcntl. Обратите внимание, как некоторые из них (F_DUPFD, F_SETFL и другие) сообщают вам, для чего используется третий аргумент. Вам нужно указать третий аргумент при использовании одного из них. Не при использовании F_GETFL или F_GETFD.

В СИНТАКСИСЕ вы можете видеть, что fcntl принимает 2 аргумента плюс ..., что означает, что третий аргумент можно опустить, если он не будет использоваться.

Проведя еще несколько исследований, я обнаружил, что есть несколько старых справочных страниц (примерно времен первого APUE), в которых СИНТАКСИС подразумевает, что требуются все 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);

Я не могу найти никаких доказательств того, что это когда-либо было объявлено таким образом в заголовке, но если бы это было так, то компиляция завершилась бы неудачей, если бы она вызывалась только с двумя аргументами. Это было бы хорошей причиной для включения в код дополнительного аргумента 0.

Если моя догадка верна и это фактическая причина исторического использования 3-arg F_GETFL, то это бесполезное ископаемое из тех времен, когда прототипы функций были новыми и страшными, а поставщики ОС ошибались в них.

person Community    schedule 31.07.2014
comment
POSIX говорит: Значения arg для F_GETFD, F_SETFD, F_GETFL и F_SETFL представляют собой значения флагов для обеспечения возможности расширения в будущем. т. е. неясно, всегда ли fcntl(fd, F_GETFL) совпадает с fcntl(fd, F_GETFL, 0) в соответствии с документацией. . Также может быть система, которая не соответствует документации. - person jfs; 31.07.2014
comment
Интересный. Я не заметил этого в ПРИМЕЧАНИЯХ ПО ПРИМЕНЕНИЮ. Я думаю, что это просто плохо написанное предупреждение. Для функций SET arg фактически является набором флагов, но функции GET возвращают флаги. Они хотят сказать, что вы не должны слепо вызывать fcntl(fd, F_SETFL, O_NONBLOCK) для включения интересующего вас флага, потому что вы можете отключить некоторые другие флаги, о которых вы не знаете. - person ; 31.07.2014
comment
И последний гвоздь в гроб вашей теории о том, что вам, возможно, придется предоставить третий аргумент в какой-то гипотетической POSIX-совместимой системе, заключается в том, что в спецификации нет ничего, что говорило бы вам, каким значением должен быть этот аргумент! Вы выбрали 0 из чистой интуиции, видимо. Если бы предполагалось, что 0 всегда следует указывать в качестве проверки версии, то число 0 действительно упоминалось бы, а не оставалось для догадок. - person ; 31.07.2014
comment
См. спецификацию POSIX для fcntl(). Он не делает замечаний о значениях аргументов для зарезервированных операций «геттера». Операции 'setter' различны. Некоторым из "геттеров" (например, F_GETLK) требуется третий аргумент. - person Jonathan Leffler; 31.07.2014
comment
@JonathanLeffler: поиск по коду предполагает, что fcntl(fd, F_GETFL, 0) является общим. Я не понимаю, почему. - person jfs; 31.07.2014
comment
Согласно этому поиску кода, одно место, где он был обнаружен, находится в APUE, что, вероятно, объясняет большинство других попаданий. Оттуда этому научились многие. Теперь вопрос: ВАПЕ давал повод? У меня нет книги. - person ; 31.07.2014
comment
@WumpusQ.Wumbley: я просмотрел где APUE упоминает F_GETFD и не нашел причину: почему он использует fcntl(fd, F_GETFL, 0) вместо fcntl(fd, F_GETFL). - person jfs; 31.07.2014

В базовой системе FreeBSD используются как fcntl(fd, F_GETFL), так и fcntl(fd, F_GETFL, 0). Но в большинстве случаев используется третий аргумент 0. Это может быть связано с историческими причинами, поскольку fcntl восходит к 4.2BSD и был импортирован во FreeBSD через исходный код 4.4BSD-Lite.

В 4.4BSD (и FreeBSD 2.0) на странице руководства указан аргумент как обязательно: int fcntl(int fd, int cmd, int arg), даже несмотря на то, что настоящий заголовок старой школы делает нет: int fcntl(int, int, ...).

Что касается почему, ответить будет сложно. Мы должны были бы спросить оригинального автора (ов). Но поскольку в исходных тегах управления исходным кодом не записаны имена (пользователей), я не знаю, как их отследить.

Дополнительный аргумент 0, вероятно, никогда не удалялся из кодовой базы FreeBSD, потому что он ничего не ломает и поэтому не настолько важен, чтобы его можно было «исправить».

person Roland Smith    schedule 05.08.2014

Эти два вызова

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

эквивалентны, потому что третий вариативный параметр игнорируется. Если вы посмотрите на fs/fcntl.c:262 и fs/fcntl.c:269 вы увидите, что arg не используется.
Однако , когда вам нужно установить какое-то значение, вы должны передать значение, которое хотите установить.
Вы можете рассматривать fcntl как ООП-эквивалент геттеров и сеттеров.

Есть ли система, для которой требуется третий аргумент: 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) давать разные результаты сегодня или в будущем (при условии совместимой реализации)?

Будущее — это тайна. Сегодня я чувствую себя достаточно уверенно, чтобы исключить это. Однако в прошлом это могло быть так.

person edmz    schedule 31.07.2014
comment
Исходник предназначен для Linux (и соответствует документации, в которой для параметра указано void). Вопрос: он портативный? Могут ли fcntl(fd, F_GETFL) и fcntl(fd, F_GETFL, 0) возвращать разные результаты в какой-то системе (в прошлом, сегодня и в будущем (при соответствующей реализации))? - person jfs; 31.07.2014