Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting to void doesn't remove warn_unused_result error

Tags:

c

gcc

gcc-warning

In a test, I'm discarding anything from stderr since it clutters the output of the test case. I'm using the following code:

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

When compiling with -Wall -Werror, I get the error

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

which is expected. However, the usual solution of casting to void doesn't seem to work. That is, changing the code to

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

still produces the same warning. I don't care if this function fails since the worst case scenario is a bit of extra output. Any other way I can fix this?

EDIT: I know I could introduce an extra unnecessary variable. I would really like to know why casting to void doesn't work.

UPDATE: I decided to go with this:

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

After reading the freopen documentation more carefully, I see that if opening /dev/null fails, stderr will still be destroyed. This solves that problem.

like image 863
Michael Mior Avatar asked Sep 01 '10 02:09

Michael Mior


4 Answers

A little heavy on the GCC extensions, but no externally visible variables:

#define ignore_result(x) ({ typeof(x) z = x; (void)sizeof z; })
ignore_result(freopen("/dev/null", "w", stderr));
like image 119
Hugh Avatar answered Nov 17 '22 02:11

Hugh


Why not simply use the result, as the warning suggests you should.

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

Since the function is declared with the 'warn_unused_result' attribute, you will get the warning unless you use the return value. Since the function either returns null on failure or the file stream argument on success, you might think about assigning the result. However, you should not assign to stderr like that (see below), so this is a bad idea:

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

Theoretically, you should make that check; there are dire (and implausible) circumstances under which you could fail to open "/dev/null".


Footnote 229 in the C99 standard notes:

229) The primary use of the freopen function is to change the file associated with a standard text stream (stderr, stdin, or stdout), as those identifiers need not be modifiable lvalues to which the value returned by the fopen function may be assigned.

Therefore, the assignment is ill-advised. But testing the return value would deal with the compiler warning and might help prevent core dumps too. It is unlikely to improve your code coverage figures, though (the error path is not going be taken very often; it will be hard to force coverage of the error handling).

Note that the POSIX description of freopen() has some moderately caustic comments about the design of freopen(), which was invented by the C standard committee (1989 version), presumably without input from POSIX.

like image 27
Jonathan Leffler Avatar answered Nov 17 '22 01:11

Jonathan Leffler


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

As comments below try

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

and

(void *)freopen("/dev/null", "w", stderr);
like image 20
Hogan Avatar answered Nov 17 '22 00:11

Hogan


If you really have to use the C language (not C++) then you may use this workaround:

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

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

For example

typedef struct A
{
    int x;
} A;

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

int main()
{
    IGNORE_RESULT(GetA());
    return 0;
}
like image 2
Sergey Shandar Avatar answered Nov 17 '22 01:11

Sergey Shandar