Thomas Sampson

Silencing ‘Unused Variable’ Warnings

Leave a comment

Warnings generated by C++ compilers which inform you that your code has ‘unused’ or ‘unreferenced’ variables in undoubtedly a good thing. Warnings such as this usually suggest that a variable can be removed (perhaps it was a debug or temporary variable a frantic coder neglected to remove) or perhaps a variable which is not being properly assigned or accessed due to a typo or re-factoring cock-up. However there are instances where this kind of warning can prove troublesome, especially when warnings are treated as errors (a discipline I strongly advocate).

More specifically, this kind of warning can become difficult to cure within code heavily plagued with pre-processor conditions (either inlined or included via some ‘clever’ macro) which control which lines or sections of code are stripped and included under a projects often plentiful build configurations. Such mechanisms can prove very powerful, perhaps to strip all debug code from a particular build, or include specific code segments per platform. However code littered with nested conditional sections such as this often become messy and difficult to manage. As a result, some variables (which are in-fact referenced multiple times within the file) become un-referenced when building with a particular build configuration.

A Very Basic Example

Within the following code the msg variable is used within debug builds but becomes obsolete when carrying any non-debug build, yielding the compiler warning in question:

#include <stdio.h>

#if defined(_DEBUG)
#define DEBUG_PRINT( x ) printf((x));
#else
#define DEBUG_PRINT( x )
#endif

void main()
{
	const char* msg = "Some Debug Message";
	DEBUG_PRINT(msg);
}

The Solution?

In a case as simple as the above it might be tempting to checkout the DEBUG_PRINT macro and upon discovering that this macro only uses its parameter when _DEBUG is defined, nest the declaration of the msg variable within an identical conditional section. This will work perfectly in such a contrived scenario but when working with larger more complex codebases this approach can involve trawling through numerous nested macros and expansions, and may only fix the problem under a particular build configuration. Perhaps a better approach is to wrap the offending variable with the following macro which tricks the compiler into having used the variable under all build configurations (provided the macro is included within all build configurations of course).

#include <stdio.h>
#define ALWAYS_USE( x ) do { } while( &(x) != &(x) )

#if defined(_DEBUG)
#define DEBUG_PRINT( x )...
#endif

void main()
{
	const char* msg = "Some Debug Message"; ALWAYS_USE(msg);
	DEBUG_PRINT(msg);
}

The ALWAYS_USE macro shown above will make the compiler believe that the msg variable is always being used, however it’s contribution to the final executable should be non-existent when compiler optimisations are enabled (or at worst generate a NOP instruction on some compilers).

MSVC Generated Assembly NDEBUG (/O2)

void main()
{
    00F01000  xor   eax,eax 
    00F01002  ret
}
Advertisements

Author: tomtech999

I have recently graduated with a 1st class degree in MComp Games Software Development at Sheffield Hallam University, focusing primarily on application development in C++, with experience in graphics programming, scripting languages, DVCS/VCS and web technology. In my spare time I enjoy Drumming, Reading and Snowboarding!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s