Table of "safe" methods to suppress "unused parameter" warnings?

M

mathog

Sometimes the same parameter list must be passed to a lot of different
functions, and some of those will not use all of the parameters,
resulting in some compilers emitting "unused parameter" warnings. Here
are all of the methods I have found so far for suppressing these:

This first set of UNUSED's are applied where the parameters are declared
in the function, as in

int function( UNUSED(x)){

#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif

The main problem with these is that the method only works for compilers
and tools that define a way to ignore the extra parameter in this
manner. It also ruins the readability of the function declarations.

This second set of UNUSED's is more general and it is applied within the
function like:

int function (x){
UNUSED(x);

#define UNUSED(x) ((void)x)
#define UNUSED(x) x=x
#define UNUSED(x) ( *(volatile typeof(x) *)&(x) = (x); )
#define UNUSED(x) if(x);

Unfortunately the members of the second set tend to convert the "unused
parameter" message into some variant of a "this line does nothing"
message on other compilers. For instance, that is what the "x=x" form,
which works with gcc does when clang sees it.

What I'm wondering is if any of you have a table of compiler
identification macros vs. members of the second set, that can be used in
a header file to pick the appropriate method for each compiler, so that
compilation with the strictest warnings is silent about unused
parameters. Like this (this example is entirely made up, I am NOT
saying that the associations below are correct):

#if defined (__GNUC__)
#define UNUSED(x) x=x
#elif defined (__CLANG__)
#define UNUSED(x) ((void)x)
#elif defind (__INTELC__)
#define UNUSED(x) ( *(volatile typeof(x) *)&(x) = (x); )
/* etc. */
#endif

There is one other method I know of, which is to actually use the
parameter "harmlessly", but it has its own issues. For instance to do

extern unsigned int junk;

and within the function

if(x)junk++;

With junk defined globally in the c file that holds main(). If the
compiler only sees one module at a time it cannot tell if junk will ever
be used, so it should not give any warnings. If the program is a single
file though, or all modules are compiled together, the compiler will be
able to detect that nothing is actually happening and issue warnings to
that effect.


Thanks,

David Mathog
 
B

Barry Schwarz

If the parameter x is not a function pointer, why not use the simpler
(void)x;

If x is a function pointer, a couple of options come to mind
(void*)x;
or
if (0) x(appropriate dummy arguments);
or if the compiler generates a diagnostic for the if expression being
constant then you could use an expression you know to be false but the
compiler would not, such as
if (agrc < 0) x(...);
 
K

Keith Thompson

Barry Schwarz said:
If the parameter x is not a function pointer, why not use the simpler
(void)x;

If x is a function pointer, a couple of options come to mind
(void*)x;
or
if (0) x(appropriate dummy arguments);
or if the compiler generates a diagnostic for the if expression being
constant then you could use an expression you know to be false but the
compiler would not, such as
if (agrc < 0) x(...);
[...]

The

(void)x;

version is perfectly valid whether x is a function pointer or not.

BTW, argc, assuming it's the conventional first argument to main,
isn't visible outside main, unless you've declared something with
that name yourself.
 
J

Javier Lopez

El 26/03/2014 18:55, Barry Schwarz escribió:
If the parameter x is not a function pointer, why not use the simpler
(void)x;
This works for pointer to function, at least on gcc 4.6.3.
If x is a function pointer, a couple of options come to mind
(void*)x;
or
if (0) x(appropriate dummy arguments);
or if the compiler generates a diagnostic for the if expression being
constant then you could use an expression you know to be false but the
compiler would not, such as
if (agrc < 0) x(...);
Unless you don't care about CPU cycles, it's better to see a compiler
warning than to write code the compiler cannot optimize out.
 
K

Kaz Kylheku

El 26/03/2014 18:55, Barry Schwarz escribió:
This works for pointer to function, at least on gcc 4.6.3.

(void) x works even if x is a struct. Though the standard doesn't seem
to spell it out, any expression can be converted to void, which results
in a "void expression" that is evaluated for its side effects only.

Also, the void type is the only non-scalar type that may be used in a cast.
Furthermore, the constraint that the operand be scalar does not apply
if the cast is to (void).
 
M

mathog

Here is a small example program to test these methods on
various compilers. The results I found follow the program.
(I don't have access to all that many compilers, and some of them are
very old.)

---cut here -- test_unused.c --
#include <stdlib.h>
#include <stdio.h>

#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif


void method1(int x){
(void) x;
printf("method 1\n");
}

void method2(int x){
x = x;
printf("method 2\n");
}

void method3(int x){
*(volatile typeof(x) *) &(x) = (x);
printf("method 3\n");
}

void method4(int x){
if(x){};
printf("method 4\n");
}

void method5(int UNUSED(x)){
printf("method 5\n");
}

int main(void){
method1(1);
method2(1);
method3(1);
method4(1);
method5(1);
exit(EXIT_SUCCESS);
}
---cut here ----

Results:

(gcc 4.6.3 and 4.7.2 tested, they did the same thing)
gcc -Wall -Wextra --std=c99 -o test_unused test_unused.c
warns:
test_unused.c: In function 'method3':
test_unused.c:24:4: error: unknown type name 'typeof'
test_unused.c:24:22: error: expected ')' before 'x'
test_unused.c:24:25: error: expected ')' before '*' token

gcc -Wall -Wextra -o test_unused test_unused.c
no warnings

(Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on
LLVM 3.0))
clang -Wall -o test_unused test_unused.c
warns:
test_unused.c:20:6: warning: explicitly assigning a variable
of type 'int' to itself [-Wself-assign]
x = x;
~ ^ ~

(A very old version of the intel linux compiler == 9.0)
iccbin -Wall -std=c99 -gcc-version=340 -i-static \
-o test_unused test_unused.c
warns about "external definition with no prior declaration" for all
of the functions, but did not warn about anything else.

(A very old version of the Sun Forte Developer 7.0 C 5.4
on an equally old Sparc)
cc -o test_unused test_unused.c
warns:
"test_unused.c", line 25: warning: no explicit type given
"test_unused.c", line 25: syntax error before or at: typeof
"test_unused.c", line 29: type specifier can not be used as array size
expression qualifier
"test_unused.c", line 29: warning: no explicit type given
"test_unused.c", line 29: cannot recover from previous errors

And that's all the compilers I have to test.


Regards,

David Mathog
 
J

Javier Lopez

(gcc 4.6.3 and 4.7.2 tested, they did the same thing)
gcc -Wall -Wextra --std=c99 -o test_unused test_unused.c
warns:
test_unused.c: In function 'method3':
test_unused.c:24:4: error: unknown type name 'typeof'
test_unused.c:24:22: error: expected ')' before 'x'
test_unused.c:24:25: error: expected ')' before '*' token
typeof is a GNU C extension, so enabling c99 disables GNU extensions
see http://gcc.gnu.org/onlinedocs/gcc/Typeof.html
(A very old version of the intel linux compiler == 9.0)
iccbin -Wall -std=c99 -gcc-version=340 -i-static \
-o test_unused test_unused.c
warns about "external definition with no prior declaration" for all
of the functions, but did not warn about anything else.
This goes away if you forward-declare the functions.
(A very old version of the Sun Forte Developer 7.0 C 5.4
on an equally old Sparc)
cc -o test_unused test_unused.c
warns:
"test_unused.c", line 25: warning: no explicit type given
"test_unused.c", line 25: syntax error before or at: typeof
"test_unused.c", line 29: type specifier can not be used as array size
expression qualifier
"test_unused.c", line 29: warning: no explicit type given
"test_unused.c", line 29: cannot recover from previous errors
See above
And that's all the compilers I have to test.
You should be using (void)x regardless the compiler as any of them
accept it and can optimize that out.
 
I

Ian Collins

mathog said:
Sometimes the same parameter list must be passed to a lot of different
functions, and some of those will not use all of the parameters,
resulting in some compilers emitting "unused parameter" warnings. Here
are all of the methods I have found so far for suppressing these:

I wonder why C doesn't just follow C++ and allow unnamed parameters?
 
K

Kenny McCormack

I've found __typeof to be reasonably portable (supported by gcc, xlc, pgcc and icc).

Thomas

In comp.lang.c, there is no such thing as "reasonably" portable.

(The old saw about being "sorta pregnant" comes to mind...)
 
D

David Brown

I've found __typeof to be reasonably portable (supported by gcc, xlc, pgcc and icc).

Thomas

Even if typeof is accepted by the compiler, the usage here is /really/
bad - it forces a volatile write to the function's parameter which will
undoubtedly generate extra code, and may force a number of additional
effects such as blocked optimisations, copying of register parameters
into a stack frame (which may in itself force the use of a stack frame
that could otherwise be omitted), etc.

It also means that if you have more sophisticated optimisation at play,
such as inlining, function cloning, etc., then you will make a mess with
such extra volatile accesses.

The simple "(void) x" should work on all compilers and produce no effect
on the code.
 
T

Tim Rentsch

mathog said:
Sometimes the same parameter list must be passed to a lot of
different functions, and some of those will not use all of the
parameters, resulting in some compilers emitting "unused
parameter" warnings. Here are all of the methods I have found so
far for suppressing these [snipping the first kind; the second
kind] of UNUSED's is more general and it is applied within the
function like:

int function (x){
UNUSED(x);

#define UNUSED(x) ((void)x)
#define UNUSED(x) x=x
#define UNUSED(x) ( *(volatile typeof(x) *)&(x) = (x); )
#define UNUSED(x) if(x);

Unfortunately the members of the second set tend to convert the
"unused parameter" message into some variant of a "this line does
nothing" message on other compilers. For instance, that is what
the "x=x" form, which works with gcc does when clang sees it.
[snip]

I suggest trying this form:

#define UNUSED(x) ( (void) (0 ? 0 : &(x)) )

or perhaps this alternate definition:

#define UNUSED(x) ( (void) (0 ? &(x) : &(x)) )

I'm interested to hear what you results you get if you
try these with different compilers.
 
T

Tim Rentsch

Ian Collins said:
I wonder why C doesn't just follow C++ and allow unnamed parameters?

Assuming for the sake of discussion that C did this, it
still doesn't solve the problem, because sometimes you
want the parameter name there but still have it not used,
eg, when a function body has multiple definitions under
control of a C preprocessor conditional. And there are
variables besides parameter names that are important to
mark UNUSED in certain circumstances.
 
I

Ian Collins

Tim said:
Assuming for the sake of discussion that C did this, it
still doesn't solve the problem, because sometimes you
want the parameter name there but still have it not used,
eg, when a function body has multiple definitions under
control of a C preprocessor conditional.

I disagree. Allowing unnamed parameters would address the exact problem
stated in the question. I don't see how multiple definitions under
control of a C preprocessor conditional would make a difference. If an
"unused" parameter is used in the function body, you have a bug waiting
to happen. It would be better to have it unnamed to allow the compiler
to spot the mistake.

If you turn the argument on its head, why does C require parameters to
be named? There doesn't appear to be any logical reason for this rule.
And there are
variables besides parameter names that are important to
mark UNUSED in certain circumstances.

I assume you are referring to unused function return values? I don't
see how this is relevant to the original question.
 
D

David Brown

I disagree. Allowing unnamed parameters would address the exact problem
stated in the question. I don't see how multiple definitions under
control of a C preprocessor conditional would make a difference. If an
"unused" parameter is used in the function body, you have a bug waiting
to happen. It would be better to have it unnamed to allow the compiler
to spot the mistake.

If you turn the argument on its head, why does C require parameters to
be named? There doesn't appear to be any logical reason for this rule.

I disagree (at least a bit) here - I don't see any reason to have
unnamed parameters in C. If the parameter is completely useless, then
it should be removed entirely - if not, then the name is part of the
documentation for the function's interface. Just because it is not used
in this particular version of the implementation of the function, does
not mean it should not be named.

And the solution to the original problem is nothing more dramatic than
"(void) x;", which is neither hard to write nor hard to understand.

In C++, I can think of a situation where unnamed parameters make sense -
you might want a function that requires you to have an object of a
particular class but does not care about the contents. This can be used
to give compile-time checking of constraints. For example, if your
system has a global interrupt lock, then you might use a class
"InterruptDisabler" whose constructor preserves the old interrupt state
and disables interrupts, and whose destructor restores the state. A
function that expects interrupts to be disabled could take an unnamed
parameter of type "const InterruptDisabler&".
 
A

Alain Ketterlin

I disagree (at least a bit) here - I don't see any reason to have
unnamed parameters in C. If the parameter is completely useless, then
it should be removed entirely - if not, then the name is part of the
documentation for the function's interface.

I think the OP mentionned callbacks (see above, I hope I have the
quoting right), where the interface is imposed. Typically, GUI toolkits
make massive use of this, but pthread_create is another example---there
are cases where a thread does not take a parameter, and relies on shared
data only.

I've had this situation often, I would like to see unnamed parameters in
C (a simple comment solves the "documentation issue").
And the solution to the original problem is nothing more dramatic than
"(void) x;", which is neither hard to write nor hard to understand.

Agree. It is still somewhat strange to insert a statement with no
effect.
In C++, I can think of a situation where unnamed parameters make sense -
you might want a function that requires you to have an object of a
particular class but does not care about the contents. [...]

Not only. Virtual member functions are a (fairly frequent) variant of
the "callback" approach.
This can be used to give compile-time checking of constraints. For
example, if your system has a global interrupt lock, then you might
use a class "InterruptDisabler" whose constructor preserves the old
interrupt state and disables interrupts, and whose destructor restores
the state. A function that expects interrupts to be disabled could
take an unnamed parameter of type "const InterruptDisabler&".

Not sure about your last sentence... And the whole idea seems rather,
well, unusual.

-- Alain.
 
I

Ian Collins

David said:
I disagree (at least a bit) here - I don't see any reason to have
unnamed parameters in C. If the parameter is completely useless, then
it should be removed entirely - if not, then the name is part of the
documentation for the function's interface. Just because it is not used
in this particular version of the implementation of the function, does
not mean it should not be named.

How so? Consider for example a device driver interface that uses a
struct of function pointers (a pretty common case). All divers use the
same struct, but not all divers require all of the parameters that are
passed. Having the parameter unnamed clearly documents that it is unused.
And the solution to the original problem is nothing more dramatic than
"(void) x;", which is neither hard to write nor hard to understand.

True, but it is ugly. What possible harm could unnamed parameters cause?
In C++, I can think of a situation where unnamed parameters make sense -
you might want a function that requires you to have an object of a
particular class but does not care about the contents. This can be used
to give compile-time checking of constraints.

Unnamed parameters are quite common in C++, probably more common than
cases where they would be useful in C. While the potential uses aren't
a common in C, the feature would still be a useful, cost free, addition.
 
D

David Brown

mathog said:
Sometimes the same parameter list must be passed to a lot of
different functions, and some of those will not use all of the
parameters, resulting in some compilers emitting "unused
parameter" warnings. Here are all of the methods I have found so
far for suppressing these [snipping the first kind; the second
kind] of UNUSED's is more general and it is applied within the
function like:

int function (x){
UNUSED(x);

#define UNUSED(x) ((void)x)
#define UNUSED(x) x=x
#define UNUSED(x) ( *(volatile typeof(x) *)&(x) = (x); )
#define UNUSED(x) if(x);

Unfortunately the members of the second set tend to convert the
"unused parameter" message into some variant of a "this line does
nothing" message on other compilers. For instance, that is what
the "x=x" form, which works with gcc does when clang sees it.
[snip]

I suggest trying this form:

#define UNUSED(x) ( (void) (0 ? 0 : &(x)) )

or perhaps this alternate definition:

#define UNUSED(x) ( (void) (0 ? &(x) : &(x)) )

I'm interested to hear what you results you get if you
try these with different compilers.

Such code may be inefficient on some compilers (and with some options) -
if "x" has been passed in a register, the compiler may copy it onto the
stack in order for it to have an address, even though the address is not
used.

I have yet to see any reason to why anyone would need something other
than "(void) x;" as a way to say "do nothing with x". An endless supply
of suggestions of macros that mess around with "x" in weird ways does
not help anyone.

(Tool-specific annotations such as gcc "unused" attribute or PC-Lint
annotations can be a useful addition if you use those particular tools.)
 
J

James Kuyper

On 03/31/2014 07:26 AM, David Brown wrote:
....
I have yet to see any reason to why anyone would need something other
than "(void) x;" as a way to say "do nothing with x".

Because they're looking for something that will work on compilers where
(void)x doesn't work. It could "not work" in two different ways: the
compiler is too dumb to avoid wasting time evaluating 'x', even though
nothing is done with the value of that expression, or it is too "smart"
to be fooled by (void)x, and still complains either about x being
unused, or about (void)x not doing anything.

I don't know of any such compilers, but neither have I bothered testing.
I have a policy of not changing my code to turn off non-mandatory
diagnostics unless I agree that they have detected an actual problem for
which the re-write is an appropriate solution.

(void)x is one of the possibilities considered by mathog, yet it's not
the only one he considered, so I presume he found at least one platform
where it didn't work.
 
D

David Brown

I think the OP mentionned callbacks (see above, I hope I have the
quoting right), where the interface is imposed. Typically, GUI toolkits
make massive use of this, but pthread_create is another example---there
are cases where a thread does not take a parameter, and relies on shared
data only.

I missed that bit - sometimes threads in c.l.c. get so long that I have
to skip many details.

But you are right - that /is/ a good reason to have unnamed parameters
in C. If you have to fit a function into a particular general function
type, then you will sometimes be forced to have parameters that are
never used, and typically have generic names like "param1" in the
function type declaration - leaving them unnamed in the function
definition would be clear documentation that they are never used in that
particular function.

So I'll make a minor U-turn and say that unnamed parameters in C /would/
sometimes be a useful feature.
I've had this situation often, I would like to see unnamed parameters in
C (a simple comment solves the "documentation issue").


Agree. It is still somewhat strange to insert a statement with no
effect.

True, but without any standard way of handling this then "(void) x;" is
the simplest and clearest way to have a statement with no effect.
In C++, I can think of a situation where unnamed parameters make sense -
you might want a function that requires you to have an object of a
particular class but does not care about the contents. [...]

Not only. Virtual member functions are a (fairly frequent) variant of
the "callback" approach.
This can be used to give compile-time checking of constraints. For
example, if your system has a global interrupt lock, then you might
use a class "InterruptDisabler" whose constructor preserves the old
interrupt state and disables interrupts, and whose destructor restores
the state. A function that expects interrupts to be disabled could
take an unnamed parameter of type "const InterruptDisabler&".

Not sure about your last sentence... And the whole idea seems rather,
well, unusual.

I think the idea is perhaps unusual - and it is certainly heretic in
c.l.c. If you haven't done embedded development, then the idea of
"disabling interrupts" is probably a bit odd. But let's take another
example. Suppose you have some sort of lock, with two functions
"getBigLock()" and "releaseBigLock()":

extern void getBigLock(void);
extern void releaseBigLock(void);

// Don't call this unless you've got the big lock!
extern void doSomethingDangerous(void);

void foo(void) {
getBigLock();
doSomethingDangerous();
releaseBigLock();
}

void bar(void) {
doSomethingDangerous();
}


In this case, the compiler cannot help spot that bar() is going to cause
trouble - you are reliant on comments and programmer care to get the
locking right.

In C++, you could do this:

class BigLock {
public:
BigLock() { getBigLock(); }
~BigLock() { releaseBigLock(); }
}

extern void doSomethingDangerous(const BigLock&);

void foo(void) {
BigLock bl;
doSomethingDangerous(bl);
}

void bar(void) {
doSomethingDangerous();
}

bar() is now clearly a compile-time error. doSomethingDangerous()
doesn't actually do anything with the parameter - it just uses
type-checking to ensure that you have a BigLock.

With enough care, templates, and hierarchies, you can do quite a bit of
compile-time checking using types like this.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top