Stream argument with possibly unintended side effects

Потоковые побочные эффекты аргумента происходят несколько раз

Описание

Аргумент Stream с возможно непреднамеренными побочными эффектами происходит, когда вы вызываете getc(), putc(), getwc(), или putwc() с потоковым аргументом, который имеет побочные эффекты.

Аргумент Stream с возможно непреднамеренными побочными эффектами рассматривает следующее как потоковые побочные эффекты:

  • Любое присвоение переменной потока, такого как FILE *, или любое присвоение переменной более глубокого потокового типа, такого как массив FILE *.

  • Любой вызов функции, которая управляет потоком или более глубоким потоковым типом.

Количество повышенных дефектов соответствует количеству обнаруженных побочных эффектов. Когда потоковый аргумент оценен многократно в функции, реализованной как макрос, дефект повышен для каждой оценки, которая имеет побочный эффект.

Дефект также повышен на функциях, которые не реализованы как макросы, но это может быть реализовано как макросы на другой операционной системе.

Риск

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

Фиксация

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

Примеры

развернуть все

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define fatal_error() abort()

const char* myfile = "my_file.log";

void func(void)
{
    int c;
    FILE* fptr;
    /* getc() has stream argument fptr with
    * 2 side effects: call to fopen(), and assignment
    * of fptr
    */
    c = getc(fptr = fopen(myfile, "r"));
    if (c == EOF) {
        /* Handle error */
        (void)fclose(fptr);
        fatal_error();
    }
    if (fclose(fptr) == EOF) {
        /* Handle error */
        fatal_error();
    }
}

void main(void)
{
    func();

}

В этом примере, getc() вызван потоковым аргументом fptr. Потоковый аргумент имеет два побочных эффекта: вызов fopen() и присвоение fptr. Если getc() реализован как небезопасный макрос, побочные эффекты происходят многократно.

Коррекция — использование отдельный оператор для fopen()

Одна возможная коррекция должна использовать отдельный оператор в fopen(). Вызов fopen() и присвоение fptr произойдите в этом операторе, таким образом, нет никаких побочных эффектов, когда вы передаете fptr к getc().

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define fatal_error() abort()


const char* myfile = "my_file.log";

void func(void)
{
    int c;
    FILE* fptr;

    /* Separate statement for fopen()
    * before call to getc()
    */
    fptr = fopen(myfile, "r");
    if (fptr == NULL) {
        /* Handle error */
        fatal_error();
    }
    c = getc(fptr);
    if (c == EOF) {
        /* Handle error */
        (void)fclose(fptr);
        fatal_error();
    }
    if (fclose(fptr) == EOF) {
        /* Handle error */
        fatal_error();
    }
}

void main(void)
{
    func();

}

Информация о результате

Группа: Программирование
Язык: C | C++
Значение по умолчанию: на
Синтаксис командной строки: STREAM_WITH_SIDE_EFFECT
Удар: низко

Введенный в R2018a