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

Discussion in 'C Programming' started by mathog, Mar 26, 2014.

  1. mathog

    David Brown Guest

    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.
    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.
    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.
     
    David Brown, Mar 31, 2014
    #21
    1. Advertisements

  2. mathog

    David Brown Guest

    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.

    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.
     
    David Brown, Mar 31, 2014
    #22
    1. Advertisements

  3. mathog

    Stefan Ram Guest

    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).
     
    Stefan Ram, Mar 31, 2014
    #23
  4. mathog

    Kaz Kylheku Guest

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

    int foo(char *, int);
    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.
    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?
     
    Kaz Kylheku, Mar 31, 2014
    #24
  5. mathog

    Phil Carmody Guest

    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
     
    Phil Carmody, Apr 1, 2014
    #25
  6. mathog

    Stefan Ram Guest

    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"«?
     
    Stefan Ram, Apr 1, 2014
    #26
  7. mathog

    Kaz Kylheku Guest

    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).
     
    Kaz Kylheku, Apr 1, 2014
    #27
  8. mathog

    David Brown Guest

    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.
    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.
     
    David Brown, Apr 1, 2014
    #28
  9. mathog

    David Brown Guest

    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).
    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).
    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
     
    David Brown, Apr 1, 2014
    #29
  10. mathog

    Tim Rentsch Guest

    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.)
    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 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.
     
    Tim Rentsch, Apr 15, 2014
    #30
  11. mathog

    Tim Rentsch Guest

    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.
    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).
     
    Tim Rentsch, Apr 18, 2014
    #31
  12. That's not the CLC way. Kiki (and the rest of the Kikians) will not
    approve. Expect your clique membership card to be revoked.
    That's not the CLC way. Kiki (and the rest of the Kikians) will not
    approve. Expect your clique membership card to be revoked.
    That's not the CLC way. Kiki (and the rest of the Kikians) will not
    approve. Expect your clique membership card to be revoked.
     
    Kenny McCormack, Apr 18, 2014
    #32
  13. 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)?
     
    Keith Thompson, Apr 18, 2014
    #33
  14. mathog

    David Brown Guest

    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.
    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.
     
    David Brown, Apr 19, 2014
    #34
  15. mathog

    Öö Tiib Guest

    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'.
     
    Öö Tiib, Apr 23, 2014
    #35
  16. 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);
     
    Keith Thompson, Apr 23, 2014
    #36
  17. mathog

    Tim Rentsch Guest

    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".
    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.
     
    Tim Rentsch, Apr 27, 2014
    #37
  18. /* Oops! */
    int foo(register int a) { (void) &a;return a; }

    main() { printf("foo(10) = %d\n",foo(10)); }
     
    Kenny McCormack, Apr 27, 2014
    #38
  19. mathog

    Kaz Kylheku Guest

    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.
     
    Kaz Kylheku, Apr 28, 2014
    #39
  20. mathog

    Phil Carmody Guest

    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.
    You say "nonsensical", others say "decorative rather than semantic".
    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.
    They shouldn't be codified in the C standard, certainly.
    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.)
    Often, yes. But alas again, it's not always possible or
    even desirable. (Quality of later messages, for example.)
    Doesn't look like omission of a name to me.
    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.
    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.
    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
     
    Phil Carmody, May 22, 2014
    #40
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.