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


D

David Brown

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.

After this and Alain's posts, I have changed my mind. You are of course
correct that in cases where functions have to fit a particular type, you
can easily get parameters that have no function and would be best left
unnamed.
True, but it is ugly. What possible harm could unnamed parameters cause?

In the case where a function has a parameter but the current
implementation does not use it, I think it is best to name it and mark
it as unused (either by something like the gcc attribute, if that is
portable enough for the code, or by (void) x). That makes it clear that
the parameter is reserved for a purpose.

In the case where a function has extra parameters just to make it fit a
common signature, then unnamed parameters would seem better, as you are
then saying that these parameters are not really part of the function.
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.

We already pay the "cost" of unnamed parameters - they are legal in
function declarations, letting people write unhelpful declarations (like
"extern int foo(int, int)"). So yes, it would be a free feature with at
least some good uses.
 
Ad

Advertisements

D

David Brown

On 03/31/2014 07:26 AM, David Brown wrote:
...

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.

Compilers that are too dumb to avoid wasting time evaluating x in
"(void) x" are going to be even worse with the other proposed solutions.

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.

It is on his list, but there has been no indication from anyone that
there are real-world compilers that have trouble with it. If there
/are/ compilers that give warnings on "(void) x" (either complaining
about x being unused, or the statement not having an effect), then it
could be useful to hear about it. And perhaps it would be useful to
report it as a bug or "enhancement request" to the compiler vendor -
warnings that are too enthusiastic can hide /real/ problems in code.
 
S

Stefan Ram

David Brown said:
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.

Actually (I admit that I might take your sentence out of its
context here), when »x« is a variable, »x;« is the simplest
and clearest way to have a statement with no effect that
mentions this variable »x«, and, otherwise, »;« is the
simplest and clearest way to have a statement with no effect.

Everything else is written not with the language C but with
the idiosyncrasies of certain warning systems or even
programmers (colleagues?) in mind.

Sometimes, the warning systems try to adapt to less careful
or less educated programmers but annoy other programmers.
Right now, I have

-pedantic -pedantic-errors -W -Wall -Wextra -Wconversion

but then

-Wno-parentheses -Wno-unused-but-set-variable

(but the last -Wno is used only temporarily for certain code).
 
K

Kaz Kylheku

I disagree (at least a bit) here - I don't see any reason to have
unnamed parameters in C.

C already has support for unnamed parameters, namely in function declarations.

int foo(char *, int);
If the parameter is completely useless, then
it should be removed entirely

In large-scale software development, we do not always have complete freedom to
remove any function parameter we want whenever we feel that it's not necessary.

Calls to a function may be in code that we don't want to, or cannot modify.

Functions may be called through function pointers, which have many
implementations, some of which don't need to use some parameters.

C++ has unnamed parameters; so supporting unnamed parameters improves
C and C++ compatibility.
And the solution to the original problem is nothing more dramatic than
"(void) x;", which is neither hard to write nor hard to understand.

I believe that (void) x is not universally recognized by all compilers as a
use of a non-volatile x.

Also, C didn't always have void; don't we have C++ to thank for that?
 
P

Phil Carmody

Actually (I admit that I might take your sentence out of its
context here), when »x« is a variable, »x;« is the simplest
and clearest way to have a statement with no effect that
mentions this variable »x«, and, otherwise, »;« is the
simplest and clearest way to have a statement with no effect.

But it's the "(void)" part that most clearly says "this is
not supposed to do have no effect", IMHO. The intention is
not to just have no effect, it's to be clearly deliberate too.

Phil
 
S

Stefan Ram

Phil Carmody said:
But it's the "(void)" part that most clearly says "this is
not supposed to do have no effect", IMHO. The intention is
not to just have no effect, it's to be clearly deliberate too.

For an int variable »x«, I cannot see any hint in

x;

that says that the author wants this to have an effect.
Therefore, I must assume that he does not want it to
have an effect. I do not know what (void) adds to this.

(int)x;

means that »(int)x« is supposed to have an int value. So

(void)x;

means that it is not supposed to have a /value/! A cast
has nothing to do with /effects/ but with /values/.

Another example:

printf( "a" );

prints »a«. Now I take your way of showing that it is
»not supposed to do have no effect«:

(void)printf( "a" );

. What happens? Surprise! It still has the same effect!
So when (void) cannot impede the effect here, how is it to
»clearly say "this is not supposed to do have no effect"«?
 
Ad

Advertisements

K

Kaz Kylheku

But it's the "(void)" part that most clearly says "this is
not supposed to do have no effect", IMHO. The intention is
not to just have no effect, it's to be clearly deliberate too.

The intention of (void) E is exactly the opposite: it states
that E is to be evaluated for its side effects, and its side effects
only---the result value is to be discarded.

This is spelled out in ISO C.

6.3.2.2 void

The (nonexistent) value of a void expression (an expression that has type
void) shall not be used in any way, and implicit or explicit conversions
(except to void) shall not be applied to such an expression. If an expression
of any other type is evaluated as a void expression, its value or designator
is discarded. (A void expression is evaluated for its side effects.)

If x is an ordinary non-volatile-qualified variable, then "x;" has no effect,
and discards its value, and so does "(void) x;". They are both equivalent and
nonsensical. Both of them in fact leave x unused. If a non-volatile-qualified
variable has its value accessed, but that value is immediately discarded,
that abstract use of the variable can be optimized away.

Compilers which translate "(void) x;" into the meaning "pretend that x is
used, and thereby shut up unused variable warning" are doing exactly the
following: they are giving a useful meaning to a piece of nonsense that serves
no purpose and can be optimized away completely. It is similar to a conforming
extension which gives meaning to bad syntax, except that this is
good-albeit-useless syntax.

This behavior is a hack; it should not be codified as standard behavior.
Neither x; nor (void) x; should constitute a use of x, unless x is volatile.
Thre should be no special case if that is the only evaluation of x in
a function body.

The right place for asserting that "the non-use of this variable can be
ignored" is in the declaration of that variable. A nice way to achieve
that is the omission of a name.

Common Lisp gets this right:

(defun foo (x y)
(declare (ignore x) (ignorable y))
...)

Declare ignore means that "x is not used in the body; this is on purpose,
please don't warn about this". If the declaration is a lie---x is in fact used
in the body---then there can be a diagnostic!

Declare ignorable means that "If x is not used in the body, that is deliberate;
please don't warn about it". In that case, x may appear, and no diagnostic
is issued.

Ignorable is convenient for macros which might conditionally generate some
piece of code that uses a parameter, or might not. They can be simplified
by not having to conditionally add the declaration.

This would be nice to have in C:

void foo(ignore int x, ignorable int y) { ... }

perhaps in optional conjunction with omission of the name:

void foo(ignore int, ignorable int y) { ... }

If we ignore it; it needs no name. (In Lisp it does because the symbol
is a positional place holder in the lambda list).
 
D

David Brown

For an int variable »x«, I cannot see any hint in

x;

that says that the author wants this to have an effect.
Therefore, I must assume that he does not want it to
have an effect. I do not know what (void) adds to this.

It is not a human reader we want to convince here, it is the compiler
and its warnings. A plain "x" will likely trigger a warning, such as
"statement with no effect" in gcc (assuming, of course, you have a high
level of warnings enabled). These warnings are to help spot accidents
or typos - if the compiler sees just "x", it guesses that you have made
a mistake in your code.

It is the same thing as gcc warning on "if (x = y) ...", but giving no
warning on "if ((x = y)) ... ". It assumes the first version to be a
typo (with "=" instead of "=="), but the second version to be a
deliberate indication that you know what you are doing.
(int)x;

means that »(int)x« is supposed to have an int value. So

(void)x;

means that it is not supposed to have a /value/! A cast
has nothing to do with /effects/ but with /values/.

Another example:

printf( "a" );

prints »a«. Now I take your way of showing that it is
»not supposed to do have no effect«:

(void)printf( "a" );

. What happens? Surprise! It still has the same effect!
So when (void) cannot impede the effect here, how is it to
»clearly say "this is not supposed to do have no effect"«?

Indeed - the "(void)" cast is not there to make the compiler do nothing
- there was nothing for it to do in the first place (except evaluate x -
something the compiler only needs to do if x is volatile, and in that
case x is evaluated even when cast to void). It is just there to tell
the compiler that you /really/ mean do nothing with x, and therefore it
should not issue a warning.
 
D

David Brown

The intention of (void) E is exactly the opposite: it states
that E is to be evaluated for its side effects, and its side effects
only---the result value is to be discarded.

This is spelled out in ISO C.

6.3.2.2 void

The (nonexistent) value of a void expression (an expression that has type
void) shall not be used in any way, and implicit or explicit conversions
(except to void) shall not be applied to such an expression. If an expression
of any other type is evaluated as a void expression, its value or designator
is discarded. (A void expression is evaluated for its side effects.)

If x is an ordinary non-volatile-qualified variable, then "x;" has no effect,
and discards its value, and so does "(void) x;". They are both equivalent and
nonsensical. Both of them in fact leave x unused. If a non-volatile-qualified
variable has its value accessed, but that value is immediately discarded,
that abstract use of the variable can be optimized away.

Compilers which translate "(void) x;" into the meaning "pretend that x is
used, and thereby shut up unused variable warning" are doing exactly the
following: they are giving a useful meaning to a piece of nonsense that serves
no purpose and can be optimized away completely. It is similar to a conforming
extension which gives meaning to bad syntax, except that this is
good-albeit-useless syntax.

This behavior is a hack; it should not be codified as standard behavior.
Neither x; nor (void) x; should constitute a use of x, unless x is volatile.
Thre should be no special case if that is the only evaluation of x in
a function body.

This is all true - but since these warning messages are from the
implementation (the standards do not require them), it is perfectly
reasonable for the method of disabling them to be an
implementation-dependent "hack". The hack here is a good choice, in
that "(void) x;" is clearly and unambiguously asking to do nothing with
x (except evaluate it, if x is volatile). It leads to no extra object
code, is ignored by any compiler other than its effects on warning
messages, and seems to give the desired "disable the warning" effect on
most compilers (I haven't yet seen a counterexample).
The right place for asserting that "the non-use of this variable can be
ignored" is in the declaration of that variable. A nice way to achieve
that is the omission of a name.

I'd agree that this makes sense too - and things like gcc's "unused"
attribute do the same thing, but in a compiler-dependent way. Putting
the "this is not used" marker in the declaration also opens for more
optimisation, if the compiler can trust it (which it cannot for "unnamed
parameters", but could for explicitly marked unused parameters).
Common Lisp gets this right:

(defun foo (x y)
(declare (ignore x) (ignorable y))
...)

Declare ignore means that "x is not used in the body; this is on purpose,
please don't warn about this". If the declaration is a lie---x is in fact used
in the body---then there can be a diagnostic!

Declare ignorable means that "If x is not used in the body, that is deliberate;
please don't warn about it". In that case, x may appear, and no diagnostic
is issued.

Ignorable is convenient for macros which might conditionally generate some
piece of code that uses a parameter, or might not. They can be simplified
by not having to conditionally add the declaration.

This would be nice to have in C:

void foo(ignore int x, ignorable int y) { ... }

perhaps in optional conjunction with omission of the name:

void foo(ignore int, ignorable int y) { ... }

If we ignore it; it needs no name. (In Lisp it does because the symbol
is a positional place holder in the lambda list).

That would be nice - no doubts there. But I won't hold my breath
waiting for it to reach the C standards!

In the meantime, you can at least do this:

#if defined(__GNUC__)
#define ignorable __attribute__((unused))
#else
#define ignorable
#endif
 
T

Tim Rentsch

Ian Collins said:
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.

A simplified example of the scenario I was thinking of is, eg,

int
set_device_mode( int x, int y ){
#if PLATFORM_X
return platform_x_syscall( x, y );
#else
UNUSED(y);
return common_syscall( x );
#endif
}

Note that the function interface is chosen to be platform
independent so callers don't have to fool around with #if,
etc. (As it happens a code base I was working on recently
has lots of such CPP conditionals, so naturally an example
along these lines occurred to me right away.)
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 don't know if there is or isn't, but I was deliberately trying
to avoid such questions because they don't change what I was
saying, namely, that allowing unnamed parameters in function
definitions does not by itself solve the problem of needing
something like UNUSED() [even considering the question just for
unused function parameters].

<editorial>
Probably it would be okay to to allow unnamed parameters, but IMO
it would be bad to _require_ that any unused parameter also be
unnamed, eg, by having a mandatory diagnostic for such cases.
I assume you are referring to unused function return values? I
don't see how this is relevant to the original question.

I will plead no contest on this one. I took the original
posting as motivation to discuss the general problem of
avoiding "not used" diagnostics, not just for function
parameters. Personally I think it makes sense to discuss
the question more generally than just function parameters,
but I admit many or perhaps most people were considering
only the more restricted domain.
 
T

Tim Rentsch

David Brown said:
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.

Concern for such systems is not on my radar, and I would
recommend to other people it not be on their radar either. Any
developer using such a lame compiler who isn't motivated enough
or competent enough to discover even one of the obvious ways
around the problem deserves to get bad results. We're talking
about compiler technology that is nearly 50 years old, and
originally implemented in machines with 256 K of RAM, including
the OS, and no virtual memory. Bad tools should be gotten rid
of, not catered to.
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".
[snip]

Then apparently you haven't been paying attention, since one was
given in the first message of the thread, and quoted both in my
reply and your response to it (and shown again above).
 
Ad

Advertisements

K

Kenny McCormack

Tim Rentsch said:
Concern for such systems is not on my radar, and I would
recommend to other people it not be on their radar either.

That's not the CLC way. Kiki (and the rest of the Kikians) will not
approve. Expect your clique membership card to be revoked.
Any developer using such a lame compiler who isn't motivated enough or
competent enough to discover even one of the obvious ways around the
problem deserves to get bad results.

That's not the CLC way. Kiki (and the rest of the Kikians) will not
approve. Expect your clique membership card to be revoked.
We're talking about compiler technology that is nearly 50 years old, and
originally implemented in machines with 256 K of RAM, including the OS,
and no virtual memory. Bad tools should be gotten rid of, not catered to.

That's not the CLC way. Kiki (and the rest of the Kikians) will not
approve. Expect your clique membership card to be revoked.
 
K

Keith Thompson

Tim Rentsch 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 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".
[snip]

Then apparently you haven't been paying attention, since one was
given in the first message of the thread, and quoted both in my
reply and your response to it (and shown again above).

We have an assertion that compilers "tend to" warn about several
forms of the UNUSED() macro.

Is there a concrete example of a compiler that complains about
((void)x)?
 
D

David Brown

David Brown 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.

Concern for such systems is not on my radar, and I would
recommend to other people it not be on their radar either. Any
developer using such a lame compiler who isn't motivated enough
or competent enough to discover even one of the obvious ways
around the problem deserves to get bad results. We're talking
about compiler technology that is nearly 50 years old, and
originally implemented in machines with 256 K of RAM, including
the OS, and no virtual memory. Bad tools should be gotten rid
of, not catered to.

Perhaps that is the case in your little corner of the C programming
world. But there are plenty of microcontrollers around where the choice
of tools is limited, and where compilers are often quite poor (or where
good quality compilers are extremely expensive), and where a pointless
waste of cycles and code space is something to be avoided.

I would say that if you are often worrying about small performance
issues, then you should probably change toolchains and/or processor.
Mostly you should be concentrating on writing good C code, and let the
compiler turn it into efficient object code. But there is no reason for
making something as simple as a "unused parameter" marker into a waste
of time and space.
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".
[snip]

Then apparently you haven't been paying attention, since one was
given in the first message of the thread, and quoted both in my
reply and your response to it (and shown again above).

Actually, I /have/ been paying attention - and I have seen (and
re-quoted) the vague and so far unjustified concern that "(void) x"
/might/ not be enough to suppress "unused parameter" warnings, or
/might/ trigger other warnings. Despite the length of this thread,
there have been no concrete examples. So until someone can show a
definite case where the compiler gives an unused parameter warning on x,
gives the same (or another warning) on "(void) x", and gives no warning
and no extra code on some weird do-nothing-in-a-complex-way statement,
then I will continue to recommend "(void) x" as the general solution to
this problem.
 
Ö

Öö Tiib

A simplified example of the scenario I was thinking of is, eg,

int
set_device_mode( int x, int y ){
#if PLATFORM_X
return platform_x_syscall( x, y );
#else
UNUSED(y);
return common_syscall( x );
#endif
}

I have seen similar situation without preprocessor slicing:

int
do_something( int x, int y ){
// y is reserved for postponed feature; must be 0 now
unused(y);
assert(y == 0);

// further code does not use y
// ...
return something;
}

When 'NDEBUG' is defined then there may be warning without
that 'unused'.
 
K

Keith Thompson

Öö Tiib said:
I have seen similar situation without preprocessor slicing:

int
do_something( int x, int y ){
// y is reserved for postponed feature; must be 0 now
unused(y);
assert(y == 0);

// further code does not use y
// ...
return something;
}

When 'NDEBUG' is defined then there may be warning without
that 'unused'.

There is "preprocessor slicing" here; it's just hidden by the
definition of the assert() macro. Since y is used in an assert(),
it's not really unused.

You could write this as:

#ifdef NDEBUG
unused(y);
#endif
assert(y == 0);
 
Ad

Advertisements

T

Tim Rentsch

Keith Thompson said:
Tim Rentsch 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 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".
[snip]

Then apparently you haven't been paying attention, since one was
given in the first message of the thread, and quoted both in my
reply and your response to it (and shown again above).

We have an assertion that compilers "tend to" warn about several
forms of the UNUSED() macro.

I read that paragraph as offering a statement of his beliefs
rather than making an allegation of fact. So I would probably
say "opinion" rather than "assertion".
Is there a concrete example of a compiler that complains about
((void)x)?

I have a dim memory of seeing a warning out of gcc for this when
used in some unusual context. In fact seeing that is part of
what originally prompted me to look for an alternate form of
expression for a macro like UNUSED.

By the way, for defining UNUSED, it's safer to use an expression
that takes the address of x, such as (void)&x, in case x happens
to be volatile qualified.
 
K

Kenny McCormack

Tim Rentsch said:
By the way, for defining UNUSED, it's safer to use an expression
that takes the address of x, such as (void)&x, in case x happens
to be volatile qualified.

/* Oops! */
int foo(register int a) { (void) &a;return a; }

main() { printf("foo(10) = %d\n",foo(10)); }
 
K

Kaz Kylheku

By the way, for defining UNUSED, it's safer to use an expression
that takes the address of x, such as (void)&x, in case x happens
to be volatile qualified.

If the macro needs to add the & operator, it can easily
do that.

Show me the macro which takes away an unwanted & from an expression.

The unembellished name of the variable is what any macro needs to generate
whatever it needs to.
 
Ad

Advertisements

P

Phil Carmody

Kaz Kylheku said:
The intention of (void) E is exactly the opposite: it states
that E is to be evaluated for its side effects, and its side effects
only---the result value is to be discarded.

Sorry for the lateness in reply. Real life too hectic.

Your response is correct. My response was still on the
original topic of "unused parameters". Alas it got later
worded as "a statement with no effect", which expanded
the topic into general statements. So we are in complete
agreement on that point.
This is spelled out in ISO C.

6.3.2.2 void

The (nonexistent) value of a void expression (an expression that has type
void) shall not be used in any way, and implicit or explicit conversions
(except to void) shall not be applied to such an expression. If an expression
of any other type is evaluated as a void expression, its value or designator
is discarded. (A void expression is evaluated for its side effects.)

If x is an ordinary non-volatile-qualified variable, then "x;" has no effect,
and discards its value, and so does "(void) x;". They are both equivalent and
nonsensical. Both of them in fact leave x unused. If a non-volatile-qualified
variable has its value accessed, but that value is immediately discarded,
that abstract use of the variable can be optimized away.

You say "nonsensical", others say "decorative rather than semantic".
Compilers which translate "(void) x;" into the meaning "pretend that x is
used, and thereby shut up unused variable warning" are doing exactly the
following: they are giving a useful meaning to a piece of nonsense that serves
no purpose and can be optimized away completely. It is similar to a conforming
extension which gives meaning to bad syntax, except that this is
good-albeit-useless syntax.

Some people want to be warned about accidental lack of use of a parameter.
They have a right to request that as a feature of the compiler they chose
to use.
This behavior is a hack; it should not be codified as standard behavior.

They shouldn't be codified in the C standard, certainly.
Neither x; nor (void) x; should constitute a use of x, unless x is volatile.
Thre should be no special case if that is the only evaluation of x in
a function body.

The right place for asserting that "the non-use of this variable can be
ignored" is in the declaration of that variable.

Not always possible. Such decorations can affect the type of the
function, depending on what you want the parser to recognise.
(And often, the parser is not there to generate code, it's for
static code analysis. In fact, I have 4 C parsers on my machine,
and only one of them is a compiler.)
A nice way to achieve
that is the omission of a name.

Often, yes. But alas again, it's not always possible or
even desirable. (Quality of later messages, for example.)
Common Lisp gets this right:

(defun foo (x y)

Doesn't look like omission of a name to me.
(declare (ignore x) (ignorable y))

That's not asserting that non-use can be ignored at the
point declaration of the variable either. Both of the
things you've been positive about are not being demonstrated
here.
...)

Declare ignore means that "x is not used in the body; this is on purpose,
please don't warn about this". If the declaration is a lie---x is in fact used
in the body---then there can be a diagnostic!

Declare ignorable means that "If x is not used in the body, that is deliberate;
please don't warn about it". In that case, x may appear, and no diagnostic
is issued.

Ignorable is convenient for macros which might conditionally generate some
piece of code that uses a parameter, or might not. They can be simplified
by not having to conditionally add the declaration.

This would be nice to have in C:

void foo(ignore int x, ignorable int y) { ... }

perhaps in optional conjunction with omission of the name:

void foo(ignore int, ignorable int y) { ... }

It gets complex because of type semantics though. In a family of
function pointers, what if some of the parameters are ignored for
some of the functions - are they the same type? You might end
up with a DAG of type equivalence.
If we ignore it; it needs no name. (In Lisp it does because the symbol
is a positional place holder in the lambda list).

Again, your view of "need" isn't shared universally. You may
share it with the compiler, but sometimes redundancy is good
for humans to aid understanding.

Phil
 

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

Top