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 }