11

I have a problem with the unused local variable warning in GCC.

Often I have code that looks like this:

bool success = foo();
assert(success);

This is fine for debug builds. In release however, the assert compiles to nothing, and GCC gives me a warning.

What is the best way to work around this? Wrapping the bool success = with #ifdef just does not seem like a nice solution...

Johan Kotlinski
  • 25,185
  • 9
  • 78
  • 101
  • 1
    Does foo() return a value purely for debugging? – JackMc Apr 11 '11 at 19:28
  • AFAIK assertions are ignored only when a special macro/variable (like `NDEBUG`) is defined. If not defined, assertions should work in both modes. – sakisk Apr 11 '11 at 19:31
  • 3
    Mh, doesn't sound like a very good idea to me to have function which returns a `bool` to indicated success or failure only check in debug builds and just assume it succeeded in release mode. – ChrisWue Apr 11 '11 at 19:33
  • 1
    `assert(!success)` means you want to assert that there's a failure... – CharlesB Apr 11 '11 at 19:33
  • No, foo() is production code - isn't that obvious from the name? – Johan Kotlinski Apr 11 '11 at 19:38
  • ChrisWue: I get what you are saying, but somehow there always are the situations where proper error handling means doing nothing. For example, you get a packet to push to a fixed-size queue, but the queue is full - what do you do? Simple answer, just let the push fail. – Johan Kotlinski Apr 11 '11 at 19:40
  • @kotlinski: or abort the app. – jalf Apr 12 '11 at 05:51
  • 2
    But isn't that an abuse of the assert? As a maintenance programmer I would find this non-self documenting and confusing. Asserts to me are meant to check that code is being properly invoked, not that a subsystem is failing in debug builds only. This is also a violation of test what you fly, fly what you test. Why return a bool if you're just going to ignore it in the releae code? At the very least the assert would be better off in the called method at the point of failure. In your example, I often push an error entry into the last available queue slot, if I don't have a logging mechanism. – Tod Jun 01 '11 at 18:54
  • Tod: Yes, I think you are rather spot on here. – Johan Kotlinski Jun 01 '11 at 19:15

7 Answers7

8

I would probably define a macro specific to this scenario

#ifndef NDEBUG
#define verify(expression) assert(expression)
#else
#define verify(expression) expression
#endif

I prefer this approach over using a local variable because it doesn't pollute the method with values that only conditionally exist.

In general I find it very helpful to have 2 sets of macros in my projects

  • assertXXX: debug only execution
  • verifyXXX: retail + debug execution
UXkQEZ7
  • 1,114
  • 1
  • 14
  • 24
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 2
    This is nice, but has the downside that if `expression` contains function calls, they may not be optimised away. – Oliver Charlesworth Apr 11 '11 at 19:40
  • @Oli, how so? I don't see how it could be optimized away since in DEBUG it will go through assert which forces the call and in non-debug the function call just stands on it's own which can't be optimized away. – JaredPar Apr 11 '11 at 19:42
  • 2
    @Jared: That's my point. What if you don't need to be calling the functions other than to compute a value that's going to be asserted? Also, in GCC with `-Wall` at least, a standalone expression (as you'd get in non-debug mode) raises a warning/error, which takes us back to where we started! – Oliver Charlesworth Apr 11 '11 at 19:45
  • @Oli in that case you should use assert directly. The diff between assert and verify is 1) debug only assertion 2) debug and non-debug assertion. – JaredPar Apr 11 '11 at 19:45
  • @Michael gotcha. In my code bases i tend to have assert = debug, verify = debug + non-debug. So if the intent is assert only then I would use assert over verify. – JaredPar Apr 11 '11 at 19:46
  • @Oli would the `-Wall` case be due to the unconsumed return value? If so is casting to void an option with GCC? I know it is with MS C++ but it's been too long since i did serious GCC development – JaredPar Apr 11 '11 at 19:49
  • 1
    @Jared: This is the problem the OP is trying to solve. – Oliver Charlesworth Apr 11 '11 at 19:51
  • @Oli The issue the OP is struggling with is GCC complaining about an unused local, not an unused function return value. It's not 100% clear about it but they mention not liking a `#if DEBUG bool success ...` solution – JaredPar Apr 11 '11 at 19:53
  • @Jared: Yes, you're right. It's the unused variable that's the problem. – Oliver Charlesworth Apr 11 '11 at 19:55
  • @Oli: if the OP wanted `foo` not to be called in release mode, he probably would have used `assert(foo())` to begin with. The other warning you mention can be avoided via an unused attribute in the verify macro. – Dennis Zickefoose Apr 11 '11 at 19:55
  • Or `#ifndef NDEBUG`, since that's what's defined to control `assert`. – Steve Jessop Apr 11 '11 at 21:01
  • @Jared: N in NDEBUG stands for NOT, so now it's backwards. `#ifndef NDEBUG` is a double-negative but it's idiomatic, and the way to go. Also, might as well add `#endif`. – Potatoswatter Apr 11 '11 at 21:16
  • @JaredPar: and counter-intuitively `#define NDEBUG 0` *disables* asserts, same as `#define NDEBUG 1`. So to follow the idiom used in the standard it does have to be `#ifdef`, not just `#if`: `#ifdef NDEBUG #define verify(e) e #else #define verify(e) assert(e)` . Of course it's up to the application writer exactly what they define `NDEBUG` to be, so if you really don't want to do that it's probably reasonable to document that anyone defining it to anything so daft/perverse as `0` will not get sensible behavior out of your `verify` macro... – Steve Jessop Apr 11 '11 at 21:18
  • @Oli: I think the best solution is to use both macros in conjunction. OP already moved the function call out of `assert` because he always wants it. Calling the new macro `assert_eval` for example allows either `assert_eval( foo() );` or `bool success = foo(); assert_eval( success );` with no warnings. – Potatoswatter Apr 11 '11 at 21:24
8

I use a macro

#define UNUSED(x) ((void)(x))

used like so:

UNUSED(success);

macro to silence the warning and to document that the fact that the variable is unused (at least at in some builds) is intentional/ok.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
6

Don't know about GCC, but this has always worked in Microsoft Visual C++:

(void) success;

It references the variable without actually doing anything.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
1

This is a slightly more concise form Lindydancer's solution at the cost of defining a helper macro. Here is the helper macro:

#ifndef NDEBUG
#  define DEBUG_ONLY( ... ) __VA_ARGS__
#else
#  define DEBUG_ONLY( ... )
#endif

Then it can be used like so:

DEBUG_ONLY( bool success = ) foo();
assert( success );
Community
  • 1
  • 1
kalaxy
  • 1,608
  • 1
  • 14
  • 14
1

You can use a variable attribute to mark it as potentially unused.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Excellent! 8-) I have that problem in one of my libraries with a static variable definition in a header that's not always being used. Although this doesn't answer this question very well because the programmer wanted a solution that works with g++ and cl... – Alexis Wilke Oct 11 '12 at 17:17
  • Nevermind, actually this question is GCC specific! 8-) I'm mixing up with another I read just before I guess. So totally perfect. – Alexis Wilke Oct 11 '12 at 17:28
1

You can utilize the NDEBUG macro, which is defined when assert are not used, for example:

#ifndef NDEBUG
  bool success =
#endif
    foo();
  assert(success);

EDIT: This will effectively "kill" the warning, as the #ifndef will ensure that there simply is no variable to warn about.

Lindydancer
  • 25,428
  • 4
  • 49
  • 68
0

You can use the GCC-specific unused attribute. It is usually defined to a short form that is easy to remove from the code for non-GCC compilers.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131