Приведение к пустоте не устраняет ошибку warn_unused_result - PullRequest
12 голосов
/ 01 сентября 2010

В тесте я отбрасываю что-либо из stderr, так как оно загромождает вывод теста.Я использую следующий код:

freopen("/dev/null", "w", stderr);

При компиляции с -Wall -Werror я получаю ошибку

error: ignoring return value of ‘freopen’, declared with attribute warn_unused_result

, которая ожидается.Однако обычное решение приведения к void, похоже, не работает.Таким образом, изменение кода на

(void) freopen("/dev/null", "w", stderr);

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

РЕДАКТИРОВАТЬ: Я знаю, что мог бы ввести дополнительную ненужную переменную.Я действительно хотел бы знать, почему приведение к void не работает.

ОБНОВЛЕНИЕ: Я решил пойти с этим:

FILE *null = fopen("/dev/null", "w");
if (null) { fclose(stderr); stderr = null; }

После прочтения freopen Документация более тщательно, я вижу, что если открытие /dev/null не удастся, stderr все равно будет уничтожено.Это решает эту проблему.

Ответы [ 4 ]

11 голосов
/ 01 сентября 2010

Немного тяжелые расширения GCC, но нет видимых извне переменных:

#define ignore_result(x) ({ typeof(x) z = x; (void)sizeof z; })
ignore_result(freopen("/dev/null", "w", stderr));
6 голосов
/ 01 сентября 2010

Почему бы просто не использовать результат, как следует из предупреждения.

if (freopen("/dev/null", "w", stderr) == 0)
    ...oops...lost stderr...hard to report errors...

Поскольку функция объявлена ​​с атрибутом 'warn_unused_result', вы получите предупреждение, если не используете возвращаемое значение.Так как функция возвращает нулевое значение в случае сбоя или аргумент файлового потока в случае успеха, вы можете подумать о назначении результата.Однако вам не следует присваивать stderr подобное (см. Ниже), так что это плохая идея:

stderr = freopen("/dev/null", "w", stderr);

ТеоретическиВы должны сделать эту проверку;Есть ужасные (и неправдоподобные) обстоятельства, при которых вы не смогли бы открыть "/dev/null".


Сноска 229 в примечаниях к стандарту C99:

229) Основное использование функции freopen - изменение файла, связанного со стандартным текстовым потоком (stderr, stdin или stdout), так как эти идентификаторы не должны быть модифицируемыми lvalues ​​длякоторому может быть присвоено значение, возвращаемое функцией fopen.

Следовательно, присвоение не рекомендуется.Но проверка возвращаемого значения будет иметь дело с предупреждением компилятора и может также помочь предотвратить дамп ядра.Однако вряд ли это улучшит показатели покрытия кода (путь ошибок не будет использоваться очень часто; будет сложно принудительно охватить обработку ошибок).

Обратите внимание, что описание POSIX freopen() содержит некоторые умеренно едкие комментарии по поводу дизайна freopen(), который был изобретен комитетом по стандартизации C (версия 1989 года), предположительно без участия POSIX.

2 голосов
/ 09 мая 2011

Если вам действительно нужно использовать язык C (не C ++), вы можете использовать этот обходной путь:

inline void ignore_result_helper(int __attribute__((unused)) dummy, ...)
{
}

#define IGNORE_RESULT(X) ignore_result_helper(0, (X))

Например,

typedef struct A
{
    int x;
} A;

__attribute__((warn_unused_result)) A GetA()
{
    A const a;
    return a;
}

int main()
{
    IGNORE_RESULT(GetA());
    return 0;
}
2 голосов
/ 01 сентября 2010
int tossmeout = freopen("/dev/null", "w", stderr);

Как комментарии ниже, попробуйте

FILE *tossmeout = freopen("/dev/null", "w", stderr);

и

(void *)freopen("/dev/null", "w", stderr);
...