Подтвердить что ты не робот

Есть ли способ использовать fopen_s() с GCC или, по крайней мере, создать #define об этом?

Компилятор MSVC говорит, что fopen() устарел и рекомендует использовать fopen_s().

Есть ли способ использовать fopen_s() и по-прежнему быть переносимым?

Любые идеи для #define?

4b9b3361

Ответ 1

Функции Microsoft *_s не переносятся, я обычно использую эквивалентные функции C89/C99 и отключать предупреждения об отказе (#define _CRT_SECURE_NO_DEPRECATE).

Если вы настаиваете, вы можете использовать функцию адаптера (не обязательно макрос!), который делегирует fopen() на платформах, у которых нет fopen_s(), но вы должны быть осторожны, чтобы сопоставить значения errno_t кода возврата от errno.

errno_t fopen_s(FILE **f, const char *name, const char *mode) {
    errno_t ret = 0;
    assert(f);
    *f = fopen(name, mode);
    /* Can't be sure about 1-to-1 mapping of errno and MS' errno_t */
    if (!*f)
        ret = errno;
    return ret;
}

Однако я не вижу, как fopen_s() более безопасен, чем fopen(), поэтому я обычно перехожу к переносимости.

Ответ 2

если вы используете C11, fopen_s является стандартной библиотекой:

http://en.cppreference.com/w/c/io/fopen

в gcc вам нужно использовать параметр --std=C11.

Ответ 3

В коде C/С++

#ifdef __unix
#define fopen_s(pFile,filename,mode) ((*(pFile))=fopen((filename),(mode)))==NULL
#endif

В Makefile

CFLAGS += -D'fopen_s(pFile,filename,mode)=((*(pFile))=fopen((filename),(mode)))==NULL'

Обратите внимание, что при успешном завершении fopen_s возвращает 0, а fopen возвращает ненулевой указатель файла. Поэтому необходимо добавить "== NULL" в конец макроса, например:

if (fopen_s(&pFile,filename,"r")) perror("cannot open file");

Ответ 4

Многие защищенные функции Microsoft включены в Приложение К стандарта C11, но он широко не поддерживается, поэтому переносимость по-прежнему остается проблемой. В некоторых приложениях требуется повышенная безопасность; возможно, поддержка будет улучшаться в будущем.

В прошлом я сделал это так:

  #define fopen_s(fp, fmt, mode)          *(fp)=fopen( (fmt), (mode))

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

Приближение функции Alex B частично частично воспроизводит правильное поведение при отказе; он возвращает errno (= EINVAL). Его подход может быть расширен далее путем создания недопустимого исключения параметра для более полного воспроизведения поведения fopen_s.

Ответ 5

Согласно https://en.cppreference.com/w/c/io/fopen можно включить функции * _s в стандартной библиотеке:

Как и для всех функций с fopen_s границ, fopen_s гарантированно будет доступен только в том случае, если __STDC_LIB_EXT1__ определен реализацией и если пользователь определяет __STDC_WANT_LIB_EXT1__ для целочисленной константы 1 перед включением <stdio.h>.

Ответ 6

#define fopen_s(fp, fmt, mode)  ({\
    *(fp)=fopen( (fmt), (mode));\
    (*(fp) ) ? 0:errno;\
})