Почему я не могу использовать fopen? - PullRequest
25 голосов
/ 25 мая 2009

В форме на предыдущий вопрос, который я задал о так называемых безопасных устареваниях библиотеки , я так же удивляюсь, почему fopen() следует считать устаревшим.

Функция принимает две строки C и возвращает FILE * ptr или NULL при ошибке. Где проблемы безопасности потока / проблемы переполнения строки? Или это что-то еще?

Заранее спасибо

Ответы [ 6 ]

46 голосов
/ 25 мая 2009

Вы можете использовать fopen(). Серьезно, не обращайте внимания на Microsoft здесь, они наносят вред программистам, отступая от стандартов ISO. Кажется, они думают, что люди, пишущие код, как-то безумны и не знают, как проверить параметры перед вызовом библиотечных функций.

Если кто-то не хочет изучать тонкости программирования на С, у него действительно нет никакого дела. Они должны перейти на более безопасный язык.

Похоже, что это просто очередная попытка Microsoft заблокировать вендора разработчиками (хотя они не единственные, кто пытается это сделать, поэтому я специально не ругаю их). Я обычно добавляю:

#define _CRT_SECURE_NO_WARNINGS

(или вариант "-D" в командной строке) для большинства моих проектов, чтобы компилятор не беспокоил меня при написании совершенно корректного, допустимого кода на языке C.

Microsoft предоставила дополнительные функции в функции fopen_s() (например, кодировки файлов), а также изменила способ возврата. Это может сделать его лучше для программистов Windows, но делает код по своей природе непереносимым.

Если вы когда-нибудь собираетесь писать код только для Windows, обязательно используйте его. Я сам предпочитаю возможность компилировать и запускать мой код где угодно (с минимальными изменениями).


Начиная с C11, эти безопасные функции теперь являются частью стандарта, хотя и являются необязательными. Для получения более подробной информации см. Приложение K.

20 голосов
/ 25 мая 2009

Официальный технический отчет ISO / IEC JTC1 / SC22 / WG14 (язык C) TR24731-1 (интерфейсы проверки границ) и его обоснование доступны по адресу:

Существует также работа в направлении TR24731-2 (функции динамического распределения).

Заявленное обоснование для fopen_s():

6.5.2 Функции доступа к файлам

При создании файла функции fopen_s и freopen_s повышают безопасность, защищая файл от несанкционированного доступа, устанавливая его защиту и открывая файл с монопольным доступом.

В спецификации сказано:

6.5.2.1 Функция fopen_s

Синопсис

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
errno_t fopen_s(FILE * restrict * restrict streamptr,
                const char * restrict filename,
                const char * restrict mode);

время выполнения-ограничений

Ни один из streamptr, filename или mode не должен быть нулевым указателем.

Если есть нарушение ограничения времени выполнения, fopen_s не пытается открыть файл. Кроме того, если streamptr не является нулевым указателем, fopen_s устанавливает *streamptr в нулевой указатель.

Описание

Функция fopen_s открывает файл, именем которого является строка, на которую указывает filename и связывает с ним поток.

Строка режима должна быть такой же, как описано для fopen, с добавлением, что режимы запускаются с символом ’w’ или ’a’ может предшествовать символ ’u’, см. ниже:

  • uw усечение до нулевой длины или создание текстового файла для записи, разрешения по умолчанию
  • ua append; открыть или создать текстовый файл для записи в конце файла, разрешения по умолчанию
  • uwb усечение до нулевой длины или создание двоичного файла для записи, разрешения по умолчанию
  • uab append; открыть или создать двоичный файл для записи в конец файла, по умолчанию разрешения
  • uw+ усечение до нулевой длины или создание текстового файла для обновления, разрешения по умолчанию
  • ua+ append; открыть или создать текстовый файл для обновления, запись в конец файла, по умолчанию разрешения
  • uw+b или uwb+ усечь до нулевой длины или создать двоичный файл для обновления, по умолчанию разрешения
  • ua+b или uab+ append; открыть или создать двоичный файл для обновления, запись в конец файла, разрешения по умолчанию

В той степени, в которой базовая система поддерживает концепции, файлы, открытые для записи должен быть открыт с эксклюзивным (также известным как не-общий) доступ. Если файл в настоящее время создан, и первый символ строки режима не является «u», в той степени, в которой Базовая система поддерживает это, файл должен иметь разрешение на файл, которое предотвращает пользователи в системе от доступа к файлу. Если файл создается и первый символ из строки режима равно «u», то к моменту закрытия файла он должен иметь системные права доступа к файлам по умолчанию 10) .

Если файл был успешно открыт, то указатель на FILE, на который указывает streamptr будет установлен указатель на объект, управляющий открытым файлом. В противном случае указатель FILE, на который указывает streamptr, будет иметь нулевой указатель.

Возвращает

Функция fopen_s возвращает ноль, если она открыла файл. Если он не открыл файл или если было нарушение ограничения времени выполнения, fopen_s возвращает ненулевое значение.

10) Это те же разрешения, с которыми файл был бы создан с помощью fopen.

8 голосов
/ 10 июля 2009

Функция fopen_s() была добавлена ​​Microsoft в среду выполнения C со следующими принципиальными отличиями от fopen():

  • если файл открыт для записи ("w" или "a", указанные в режиме), то файл открывается для монопольного (не общего) доступа (если платформа поддерживает его).
  • если спецификатор "u" используется в аргументе mode со спецификаторами "w" или "a", то к моменту закрытия файла он будет иметь системные разрешения по умолчанию для доступа других пользователей к файлу (что возможно, нет доступа, если это системная настройка по умолчанию).
  • если указанное «u» не , используемое в этих случаях, то когда файл закрыт (или ранее), разрешения для файла будут установлены так, что другие пользователи не будут иметь доступа к файл.

По сути это означает, что файлы, которые записывает приложение, по умолчанию защищены от других пользователей.

Они не сделали этого с fopen() из-за вероятности того, что существующий код сломается.

Microsoft решила отказаться от fopen(), чтобы побудить разработчиков для Windows принимать осознанные решения о том, будут ли файлы, используемые их приложениями, иметь потерянные разрешения или нет.

Ответ Джонатана Леффлера предоставляет предложенный язык стандартизации для fopen_s(). Я добавил этот ответ в надежде прояснить причину.

2 голосов
/ 25 мая 2009

Или это что-то еще?

В некоторых реализациях структуры FILE, используемой 'fopen', дескриптор файла определен как 'unsigned short'. Это дает вам максимум 255 одновременно открытых файлов, минус stdin, stdout и stderr.

Хотя возможность иметь 255 открытых файлов является дискуссионной, конечно, эта деталь реализации реализуется на платформе Solaris 8, когда у вас более 252 сокетных соединений ! То, что сначала выглядело как случайный сбой в установлении SSL-соединения с использованием libcurl в моем приложении, оказалось вызвано этим, но потребовалось развертывание отладочных версий libcurl и openssl и прохождение сценария отладчика для окончательного выяснения ситуации. 1009 *

Хотя это не совсем вина «fopen», можно увидеть преимущества отказа от оков старых интерфейсов; выбор не рекомендуется делать может быть основан на боли поддержки двоичной совместимости с устаревшей реализацией.

1 голос
/ 25 мая 2009

Резьба безопасности. fopen() использует глобальную переменную errno, тогда как замена fopen_s() возвращает errno_t и принимает аргумент FILE** для хранения указателя файла на.

1 голос
/ 25 мая 2009

Новые версии делают проверку параметров , тогда как старые не делают.

См. этот поток SO для получения дополнительной информации.

...