Skip to content

Guidelines: Warnings

Nikita Kniazev edited this page Mar 15, 2019 · 10 revisions

Managing Warnings from Compilers (and other tools)

Following a long thread on Boost.org following a query from Brian Kuhl of Wind River on Boost current compiler warnings, I promised to revise our only current guidance document.

This document is a revision of WarningFixes a historical record of progress made on warning fixes/suppression in Boost libraries.

Despite some updates made in the conversion from Trac to Markdown, suitable for github, it still needs updating to reflect recent tool changes and experience.

All comments, criticism (prefably gentle), additions, suggestions etc most welcome.

Avoid, Eliminate, Suppress, or Document warnings

Boost regards unheeded warnings as a Bad Thing.

But because Boost works with many platforms, many versions of many compilers, and many varying options, it is not always feasible or sensible to quiet all warnings.

Boost aims to avoid warnings messages as far as is reasonably practicable, even when compiled with the highest and most pedantic warning level, avoiding vendor specific extensions if possible.

What Boost Library Authors should do.

Boost Library Authors should try to compile their library on at least two of the major platforms at the highest warning level (choosing the warnings-as-errors option will ensure that no warnings go unnoticed). Authors should examine all warnings and decide if it is reasonably practicable to avoid, eliminate, supress, or at least comment on the warnings.

Some rationale and much detailed how-to guidance is given below.

Discussion

Warnings often indicate real problems. Sometimes they only manifest on a particular platform, revealing a portability issue. Sometimes they indicate that the code doesn't account for a runtime condition, like overflow, which the warning can only suggest as a possibility.

Suppressing a warning without altering code may simply mask a problem. The right approach is to determine why the warning occurs, to decide whether it is correct in the context, and if so, apply appropriate remediation. If the warning is not correct in the context, only then should it be suppressed.

To suppress warnings on all platforms is tedious hard work because every compiler provides different warnings and different ways of supressing warnings. Predefined compiler macros may help in pre-processing to chose the right method, but clutter the code.

#ifdef _MSC_VER
  return;
#elif __CLANG__
  return 0;
#endif 

So it is usually less trouble to eliminate the problem by better more portable coding.

Because all developers don't have the same know-how, even among Boost developers, Boost is amassing information to help them know when a warning is significant and not. That information can show cases in which a warning is legitimate and when it isn't. If legitimate, there is help to understand how to change the code portably to account for the problem revealed by the warning. If not legitimate, there is information on how to suppress the warning in a portable way.

Changing code can lead to bugs. Thus, changing code to eliminate a warning might create a bug. That's unfortunate. From a maintenance standpoint, however, most would prefer to see altered code to a glob of preprocessor and pragma line noise that suppresses a warning in the unchanged code.

Testing will reveal the bug. If it doesn't, the testing is insufficient. If the bug appears on an untested platform, then more testers are needed to be able to detect such bugs in the future.

Briefly, for some users, any warning is a bug.

Programming protocols usually enforce by setting an option like MSVC /WX or GCC -Werror, or less draconially, GCC -Werror=some_warning makes some_warning an error, and MSVC similarly allows a #pragma, for example

// Report warning 4164 as an error.
#pragma warning( error : 164 ).

If you are using b2, then Boost Build tutorial describes in the how to enforce warnings-as-errors portably with the feature <warnings-as-errors>=on (default is off).

Reasons to eliminate or suppress warnings:

  1. To allow users, whose environment requires no warnings, to use Boost code.
  2. To avoid the nuisance, perhaps overwhelming, of spurious warning messages.
  3. To improve code quality by focusing library writers' attention on potential problems.
  4. To improve portability by focusing developer attention on potentially non-portable code.
  5. To improve compliance with C++ Standard(s).
  6. To permit users using Boost libraries to set high warning levels for their code without being overwhelmed with a blizzard of warnings from Boost libraries.
  7. To document that warnings have been considered by the library author or maintainer and are considered not a significant risk.
  8. To aid those working with rigorous coding standards like SEI CERT Coding standards to use Boost libraries.
  9. For Boost, keeping warning suppression local is more important than just suppressing a specific warning.

What to do - detailed suggestions and notes.

1 Test compilation with the most pedantic setting for the compiler, and non-debug mode.

For Microsoft Visual Studio, this means setting level to 4 (command line /W4).

If you are working with a recent or current Microsoft compiler, then for Visual Studio 2017 version >= 15.5 (June 2018), one can control checks on conformance with the chosen standard, c++11, 14, 17, latest. See (https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=vs-2017)

If you are dealing with an older Microsoft compiler then you might imagine that it would be a good idea to compile with the /Za option to disable MS extensions, but this will not be as useful as one might hope for reasons explained by Stephan T. Lavavej from the Microsoft STL team in an authoritative post at /Za and Warning Guidelines for VC. And more seriously, when using Boost libraries, standard-conforming name lookup is broken. See (https://connect.microsoft.com/VisualStudio/feedback/details/486253/name-lookup-broken-with-za) and note that it has a won't fix status.

Briefly, don't use /Za for ANYTHING. It's broken!

There are several problems:

  • Firstly, the latest compilers, especially VC14, is "pretty conformant" and so code is likely to be portable anyway.
  • Secondly, there is a compiler bug(s) which means that valid standard-conforming code fails to compile, and this is marked 'won't fix'.
  • Thirdly, is the probable need to link to other libraries, for example regex, serialization that also must be built with the /Za option, but some will fail to compile.
  • Finally, since there is no way to distinguish libraries built with and without this option by filename, so that they cannot co-exist: this is a recipe for confusion and trouble!

The ultimate test of C++ code portability is still testing on as wide a variety of platforms as possible.

You might also consider using Microsoft /Wall if available. You may find Geoff Chappell's Visual C++ guide a helpful (if dated) guide to the Byzantine complexity of warnings from Microsoft tools.

Having said that, if you only have access to a Microsoft platform, before launching code on the full array of testers, you might consider checking if any indications of non-portability emerge from testing with language extensions disabled, or the /permissive- (conformance checking).

But you will probably just find spurious compilation failures.

To do this, (for code that doesn't deliberately use Microsoft language extensions), use the VS IDE to disable them with Disable MS extensions = Yes, which adds command line option /Za.

To a jamfile add <toolset>msvc:<cxxflags>/Za # Disable MS extensions.

If it proves impossible to compile with the /Za option (it causes trouble with some MS compilers, sometimes), just document this, including a comment in the build Jamfile.

If only one (or a few) modules in a test (or other) build require MS extensions, you can selectively 'switch off' this 'disable' in the requirements in the Jamfile, for example:

# pow test requires type_of that MS extensions.
run pow_test.cpp ../../test/build//boost_test_exec_monitor
  : # command line
  : # input files
  : # requirements
    -<toolset>msvc:<cxxflags>/Za # Requires type_of which requires MS extensions, 
       # so cancel /Za to enable extensions.
  : test_pow
;

Note the leading minus - switches off the compiler switch /Za, producing output thus:

compile-c-c++ ..\..\..\bin.v2\libs\math\test\test_pow.test\msvc-9.0\debug\asynch-exceptions-on\threading-multi\pow_test.obj
pow_test.cpp
using native typeof

Making Visual Studio options the default for all projects

If you really, really wish to make all of your VS projects in all VS solutions compile with other options by default, you might consider (carefully) editing the VC wizard.

Editing the VC wizard

You can use any text editor, very carefully, to change from the Microsoft defaults, after saving a copy of the original of the file C:\Program Files\Microsoft Visual Studio 9.0\VC\VCWizards\1033\common.js (or similarly for other releases, C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\VCWizards\1033\common.js for VS 2017) . This file is read-only, so you will need to enable editing while you make the changes. This does not seem to be officially documented as far as I know. It may save you changing the project properties repeatedly (and is especially useful if you find that because of previous choices, the project wizard's default is to disable extensions).

For example:

function AddCommonConfig(oProj, strProjectName,bAddUnicode,bForEmptyProject) in the sections for debug and/or release

CLTool.DisableLanguageExtensions = true; // add to make the default NO MS extensions (but you really don't want this for Boost code).

CLTool.DisableLanguageExtensions = false; // default, enable language extensions (strongly recommended for all Boost code).

LinkTool.LinkIncremental = linkIncrementalNo; // add

CLTool.WarningLevel = WarningLevel_4; // change from 3 to 4 to making the default warning level 4

For GCC** the highest warning level means -Wall -pedantic

but you will want to consider adding specific warnings that are to be suppressed, for example:

-pedantic -Wall -Wno-long-long -Wno-unused-value

but this is a global setting, so you need to document that these warnings must be suppressed by users of this module. This may be acceptable if they are building a library of entirely Boost modules.

Using b2/bjam add warnings=all to the invocation command line.

Putting options in jam files allows setting to be made for one or more specified compiler(s).

Some example options in a Jamfile
project
    : requirements
# GCC
      <toolset>gcc:<cxxflags>-Wno-missing-braces
# Clang
      <toolset>clang:<cxxflags>-Wno-missing-braces
# Darwin
      <toolset>darwin:<cxxflags>-Wno-missing-braces
# ACC
      <toolset>acc:<cxxflags>+W2068,2461,2236,4070,4069 # Comments on each warning messages would help readers who do not have ACC documentation to hand.
# Intel
     <toolset>intel:<cxxflags>-nologo
# MSVC
      <toolset>msvc:<warnings>all # == /W4
      -<toolset>msvc:<define>_DEBUG # Undefine DEBUG.
      <toolset>msvc:<define>NDEBUG # Define NO debug, or release.
      <toolset>msvc:<asynch-exceptions>on # Needed for Boost.Test

      # <toolset>msvc:<cxxflags>/Za # Disable MS extensions, strongly NOT advised - see above.
      #-<toolset>msvc:<cxxflags>/Za # (Re-)Enable MS extensions if these are definitely required for specific module.

      #  The define of macros below prevent warnings about the checked versions of SCL and CRT libraries.
      #  Most Boost code does not need these versions (as they are markedly slower).
      <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
      <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
      <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
      <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
      <toolset>msvc:<define>_CRT_NONSTDC_NO_DEPRECATE # Suppresses other warnings about using standard POSIX and C9X.
      #  Alternatively, you can just suppress the warnings (perhaps not the best way).
      <toolset>msvc:<cxxflags>/wd4996 # 'putenv': The POSIX name for this item is deprecated.
      <toolset>msvc:<cxxflags>/wd4512 # assignment operator could not be generated.
      <toolset>msvc:<cxxflags>/wd4224 # nonstandard extension used : formal parameter 'arg' was previously defined as a type.
      <toolset>msvc:<cxxflags>/wd4127 # expression is constant.
      <toolset>msvc:<cxxflags>/wd4701 # unreachable code - needed for lexical cast - temporary for Boost 1.40 & earlier.
   ...
    ;

Defining warnings as errors

Using warning-as-errors will make it hard to miss or ignore warnings. Microsoft command line option /WX, makes all warnings errors, but this may be too drastic a step for most users.

The following have been recommended by Pete Bartlett to make the MSVC and GCC compilers behave as similarly as possible:

  • /we4288 - For-loop scoping (this is the default).
  • /we4238 - don't take address of temporaries.
  • /we4239 - don't bind temporaries to non-const references (Stephan's "Evil Extension").
  • /we4346 - require "typename" where the standard requires it.

and compile options:

  • /Zc:forScope - For loop scoping again (this is the default).

  • /DNOMINMAX - Don't define min/max macros (usually only applies if windows.h is involved).

    (Note that suitable bracketing to prevent macro evaluation, for example,

    (std::numeric_limits<double>::max)(), 
    (std::numeric_limits<double>::min)(), 

    will avoid clashes with MIN/MAX macros, and is required to avoid being named'n'shamed by the Boost inspection tool. You can build the inspect tool inspect.exe and run it yourself from your library documentation /doc/html folder to find any defects like the above (and missing/broken links etc) before .

    So it is far better to check that clashes are correctly avoided by bracketing as above because others may use your code when MIN/MAX macros are defined rather than using this compiler option.)

    gcc option -warning-as-errors
    gcc option -pedantic-errors
  1. Consider each warning and
  • Rewrite the code to avoid the warning, if possible. For example, adding a static_cast will indicate that any warning about loss of accuracy has been judged not possible or significant.

    char a = static_cast<char>(i);
  • Remove or comment out parameters to avoid warnings about unused parameters. Placing /* comment */ around an unused variable name, allows the name still to be useful documentation.

    void f(bool /* number_of_thingys */) // Named but unused_parameter number_of_thingys.
    {
      ... some code not using number_of_thingys ...
      return;
    }
  • Use the compiler specific mechanism to suppress the warning message, but try very hard to ensure that this is as local to the package as possible so that other libraries users can still get warnings from their code.

For MSVC, this involves pushing to save the current warning state, disabling the warning, and later popping to restore (abbreviated here as push'n'pop). See warnings

There was a limit to how many times (56) this can be used, (and this limit might be reached in practice with Boost code), so it is always much better to 'fix' than to suppress warnings.

"The compiler only supports up to 56 #pragma warning statements in a compiland."

But it is now believed that this limit value is incorrect and that there is no practical limit, see post by Warning limit - notes by Stephan T. Lavavej.

On GCC there does not appear to be a practical limit, see post by Patrick Horgan.

For example, localize warning supression:

#if defined(_MSC_VER)
#  pragma warning(push) // Save warning settings.
#  pragma warning(disable : 4996) // Disable deprecated localtime/gmtime warning.
#endif

...

#if defined(_MSC_VER)
#  pragma warning(pop) // Restore warnings to previous state.
#endif

Adding some or all of the warning message as a comment is helpful to tell 'readers' what warning is being ignored, for example:

#  pragma warning(disable: 4510) // Default constructor could not be generated.

If the warning is only for a specific compiler version, use this approach:

#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#  pragma warning(push)
#  pragma warning(disable:4512) // Assignment operator could not be generated.
#endif

...

#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#  pragma warning(pop)
#endif
  • Repeat this process with other compilers and use their specific suppression methods.

  • If a warning cannot be eliminated or suppressed, explain why in the code and the documentation. If appropriate, document in build files, as well.

  • Consider documenting the highest warning level possible or compiler-specific settings that will provide a warning-free build.

  • If a warning only appears as false positive because is it in an #ifdef, for example:

    void f(int x) {
        // some code...
    #ifdef XYZ
        dostuff(x);
    #endif
       // more code...

    then the compiler cannot detect that it is a false positive (FP).

It has been recommended to add a line like (void) x; to suppress the warning.

Other possible workarounds (in case you have several unused variables):

  • You can use pragmas to disable some diagnostics for certain regions of code.
  • You can use compiler flags to disable some diagnostics for certain translation units.
  • You can always factor out platform dependent code to multiple files and have the #ifdef on includes.

Specific Warnings and Suggested Actions

These are just few ideas for starters, and need more, especially for GCC. Suggestions may be wrong!

Warning from Microsoft Visual Studio C++

See Microsoft C++ Compiler warnings.

If you chose to suppress (rather than fix by recoding), localise the warnings as far as possible by using push'n'pop pragmas (see above).

Warning Warning Description Suggestions Suppression
C4100 unreferenced formal parameter Either surround the parameter with C comments, for example: int /* my_variable */ or just delete if the variable name is uninformative. If in other's module(s), or you are too busy/idle, at least suppress warning. In generic code you might not be able to comment the variable name as it might actually be used to call a static function. In this case simply referencing the variable (varname;) in the function body eliminates the warning. (If you comment out, you will not be able to document the parameters using Doxygen \param my_variable, so you will need to disable the warning) #pragma warning(disable: 4100) // 'name' : unreferenced formal parameter
C4127 conditional expression is constant Very common and many believe unhelpful, but a few find it informative, so do not suppress globally. Even while(true) can trigger this! Suppress. while(true) can be rewritten as for(;;) eliminating the warning. #pragma warning(disable: 4127) // conditional expression is constant.
C4146 unary minus operator applied to unsigned type, result still unsigned This indicates a real error. Fix.
C4180 qualifier applied to function type has no meaning; ignored The meaningless qualifier can always be removed (or left as a comment if it informative) - but check that you didn't mean to put the const somewhere else. can always be suppressed. #pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
C4189 local variable is initialized but not referenced This probably indicates a redundant variable and assignment, so probably remove it. If you are sure it is required (or has negligible cost for some documentation benefit), suppress. #pragma warning(disable: 4189) //local variable is initialized but not referenced
C4224 nonstandard extension used : formal parameter 'arg' was previously defined as a type. This will bite users who try to compile with Microsoft extensions disabled. Wrong warning acknowledged by MS as a bug http://tinyurl.com/2blmq3l but won't be fixed. May be a major nuisance to change the names in the code but suppressing is fine. #pragma warning(disable: 4224) // formal parameter 'arg' was previously defined as a type.
C4244 Conversion: possible loss of data. Fix, for example changing type or using static_cast is best, suppress with much caution. #pragma warning(disable:4244) // Conversion: possible loss of data.
C4324 structure was padded due to __declspec(align()) Suppress #pragma warning(disable:4324) // structure was padded due to __declspec(align())
C4503 decorated name length exceeded Suppress. (Note that \boost\config\compiler\visualc.hpp includes this global suppression: #pragma warning(disable:4503) #pragma warning( disable : 4503 ) // warning: decorated name length exceeded
C4506 no definition for inline function Provide a definition, or if you cannot/will not, suppress. #pragma warning(disable: 4506) // no definition for inline function
C4512 assignment operator could not be generated Suppress using push'n'pop for the module(s) causing the warning. Adding the declaration (not the definition) of the appropriate operator=() as a private member does the trick as well. #pragma warning(disable: 4512) // assignment operator could not be generated.
C4511 copy constructor could not be generated. Provide constructor (and assignment operator and destructor). Or suppress. #pragma warning(disable: 4511) // copy constructor could not be generated
C4510 default constructor could not be generated. If have reference or const members provide default constructor with initializer list. If intent is to make non-default-constructable, provide private declaration only. Suppress. #pragma warning(disable: 4510) // default constructor could not be generated
C4535 calling _set_se_translator() requires /EHa Common from Boost.Test. In jamfile, add to project : requirements <toolset>msvc:<asynch-exceptions>on # calling _set_se_translator() requires /EHa
C4625 copy constructor could not be generated because a base class copy constructor is inaccessible Trying to derive from a non-copyable class? Bug? Fix.
C4626 assignmentconstructor could not be generated because a base class copy constructor is inaccessible Trying to derive from a non-copyable class? Bug? Fix.
C4671 the copy constructor is inaccessible Suppress? #pragma warning(disable: 4671) // the copy constructor is inaccessible
C4673 A throw object cannot be handled in the catch block. Fix ? #pragma warning(disable: 4673) // Thrown object cannot be handled in catch block.
C4701 local variable may be used without having been initialized Best is to recode to avoid the message, probably just initialising it. But if you are very sure the message is misleading, and cost of dummy initialisation too high, suppress. #pragma warning(disable: 4701) // local variable may be used without having been initialized
C4702 unreachable code Best delete or comment-out. Be very cautious about suppressing this, but use of macros may make this troublesome, so suppress with care, and always locally. #pragma warning(disable: 4702) // unreachable code
C4710 'function' : function not inlined If variable is volatile, suppress. #pragma warning(disable: 4510) // function not inlined.
C4725 inline assembly instruction that may not produce accurate results on some Pentium microprocessors. Now obselete. Suppress. #pragma warning(disable: 4510) // inaccurate results on some Pentium microprocessors?
C4800 int' : forcing value to bool 'true' or 'false' Use a bool valued expression. Write out expressions, for example: "value >= 0" or "ptr != 0" (Boost prefers clarity to curtness). Take care if using templates that constants are of the right type, for example you may need "value == static_cast(1)". Or use static_cast(expression). Or suppress. #pragma warning(disable: 4800) // int' : forcing value to bool 'true' or 'false'
C4996 'putenv': The POSIX name for this item is deprecated (but NOT by POSIX!). Suppress. #pragma warning(disable: 4996) // 'putenv' was declared deprecated.
C4996 ' this item is deprecated. Many similar messages suggest using secure versions. Unless you strongly believe that the 'secure' versions are useful, suppress. WG14 Austin Group concerns may guide. See also _CRT_SECURE_NO_DEPRECATE and other defines above. #pragma warning(disable: 4996) // '' was declared deprecated.
C6385 invalid data: accessing , the readable size is bytes, but bytes may be read. Code analyzer False warning C6385 when a function result is used as an array index. See [https://connect.microsoft.com/VisualStudio/feedback/details/281033/] suggests this can be suppressed, unless a check on array bounds is wanted/necessary.

Warnings from GCC

With older versions of GCC, it was more difficult to deal with warnings because there was no way to locally silence individual warnings. GCC version 4.2 first allowed suppression via pragma (actually you can choose whether a particular problem is a warning, error, or ignored). Initially one could not save the current state of affairs, so after suppressing the warning, you wouldn't know whether the user had it on, off, or causing an error. You can imagine that this would be quite annoying for users who care about these things. Also, the pragmas had to be at file scope rather than inside your code. From version 4.6 a pragma was added to push or to pop the state of diagnostics, and the pragmas now affect from the line they are specified in forward. It is considered very important not to leave warnings switched off when meeting user code. This is an unresolved difficulty when using GCC versions prior to 4.6.

So more emphasis should be placed on fixing warnings, for example using static_cast, or providing missing items.

Turning on Warnings

GCC uses command line options to turn on warnings: GNU C++ Options to Request or Suppress Warnings.

If you want to turn on warnings about unused variables you would add, for example, -Wunused-variable to the command line. Some of the command line options such as -Wall, -Wextra, and -pedantic turn on groups of warnings as detailed below. Sometimes a group is almost right, but not quite. If you want -pedantic, for example, but without warnings about the use of long long for use with C++98, you could say -pedantic -Wno-long-long. You could also say -pedantic -std=c++0x since long long is in that version of the spec.

In general, any diagnostic option specified as -Woption-name can be turned off with -Wno-option-name.

Be aware that warning groups can change over time. For the most up-to-date list follow to the documentation, or you can list enabled warnings by invoking the compiler appending -Q --help=warnings to your flags (e.g. g++ -O2 -Wall -Q --help=warnings).

  • -Wall - enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros.

    Note that some warning flags are not implied by -Wall. Some warn about constructions that users generally do not consider questionable, but which occasionally you might wish to check for; others warn about constructions that are necessary or hard to avoid in some cases, and there is no simple way to modify the code to suppress the warning. Some of them are enabled by -Wextra but many of them must be enabled individually.

  • -Wextra - enables some extra warning flags that are not enabled by -Wall. (This option used to be called -W. The older name is still supported, but the newer name is more descriptive.)

    The option -Wextra also prints warning messages for the following cases:

    • A pointer is compared against integer zero with <, <=, >, or >=.
    • (C++ only) An enumerator and a non-enumerator both appear in a conditional expression.
    • (C++ only) Ambiguous virtual bases.
    • (C++ only) Subscripting an array that has been declared register.
    • (C++ only) Taking the address of a variable that has been declared register.
    • (C++ only) A base class is not initialized in the copy constructor of a derived class.
  • -pedantic or -Wpedantic

    Tells GCC that you intend to adhere to a particular version of a language standard. Causes GCC to issue all required diagnostics of version of the C or C++ language standard as given by the -std=xxxx option.

    Also warns about the use of GCC extensions. (This would, for instance, warn about the use of #ident, which is a non-standard, GCC extension.)

    Some of the warnings this option will trigger can be suppressed, such as the use of long long in C++98 code with -Wno-long-long, but many cannot (more information in suppression section).

    Using -pedantic makes it easier to write portable code.

    Best used with explicit -std=xxxx. Much of boost uses facilities from more recent versions of the C++ standard, so it might make more sense to explicitly specify -std=c++0x, -std=c++11, or -std=c++20. See standards.

Specific Warnings and Suggested Actions

comparison between signed and unsigned integer expressions

  • -Wsign-compare - enable the warning (also turned on by -Wextra)

  • -Wno-sign-compare - disable the warning

    Almost always points to a real issue. The ranges of these are obviously different, for example:

    type range bit pattern
    signed char -128 to 127 01111111 to 10000000
    unsigned char    0 to 255 00000000 to 11111111
    That means signed char unsigned char
      0 to 127
    128 to 255

    In the range from 128 to 255 a comparison from one to the other makes no sense. They can have the same bit pattern, yet test as not equal. This is the source of many subtle and hard to find bugs.

    The same problem can occur with all of the integral types. For example with 16-bit short int unsigned ranges from -32768 to 32767, and the signed short ranges from 0 to 65535.

    To fix, if you are sure that all the values for both things being compared fall into the overlap where their values are the same, you can static_cast one type to the other, if you must, but if you can change one of the types it's a better solution. If you are sure that you can fit all values into the compared range, i.e. positive numbers from 0 to (1<<(sizeof(IntegralType)*8-1))-1, it would make more sense to declare the signed one as an unsigned equivalent, (perhaps size_t). In general, if you don't intend for a variable to ever have negative values, take advantage of the diagnostic capabilities of the compiler and declare it as an unsigned type, often size_t. After you've done this, if you see the warning again for one of these same variables, it is warning you of this same danger again.

    This often shows up with loop counters. We all learned to use int, but if it's truly counting only positive numbers, size_t is better.

missing braces around initializer for ‘main()::X

  • -Wmissing-braces - enable the warning (also turned on by -Wall)

  • -Wno-missing-braces - disable the warning

    This warning is trying to let you know that what you think you're initializing may not actually be what you're initializing.

        struct X { int i; int j;};
        struct Y { struct X x; int j; };
    
        Y y={1,2};
        return 0;

    The above example initializes both the elements of X in Y, but doesn't initialize j. Change to:

        Y y={{1},2};

    to initialize half of X and all of Y, or better something like:

        Y y={{1,2},3};

    The same kind of problem can come up with:

        int a[2][2]={ 0, 1, 2 };

    versus:

        int a[2][2]={ {0,1},2};

    or

        int a[2][2]={ 0, {1,2}};

deprecated conversion from string constant to char*

  • -Wwrite-strings - enable this warning (disabled by default for C and enabled by default for C++)

  • -Wno-write-strings - disable this warning

    For C will warn about trying to modify string constants, but only if defined const. For C++ often symptomatic of a real bug since string literals are not writeable in C++.

    This one shows up when you have a string literal, like "Hello world!" which is arguably const data, and you assign it no a non-const char* either directly or via passing as an argument to a functions which expects a non-const char *. both:

        char* cp="Hello world!";

    and

        foo(char *cp);
        foo("Hello world");

    will get this warning because you're using a string literal where a char* is expected. If you say, so what? See if you can predict what will print in the example below.

    #include <iostream>
    
    void
    foo(char *cp)
    {
        cp[0]='W';
    }
    
    int main()
    {
        char *str="Hello, world";
        foo(str);
        std::cout << str << std::endl;
    }

    If you said that Wello, world will print, think again. Your most likely output is something like:

    **Segmentation fault (core dumped)**
    

    A string literal is put into a section that is read only and trying to write to it makes things blow up!

    The right fix is to make anything that a string literal can be assigned to a const char*. Unfortunately, sometimes you can't fix the problem at the source, because it's someone else's code, and you can't change the declaration. For example, if you had this function:

    int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict,
                            char *format, char **kwlist, ...);

    and you had a keyword list to pass it that looked like this:

    static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};
            if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
                                             kwlist, &get, &set, &del, &doc))

    you would get the warning on the kwlist assignment, because you're assigning a const char * to char *, but when you correctly change it to:

    static const char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};

    to get rid of the waring you'll get a warning on the call to PyArg_ParseTupleAndKeywords:

        error: invalid conversion from ‘const char**’ to ‘char**’
    

    because the library function was declared as taking a char ** for the fourth argument. Your only recourse is to cast away the constness with a const_cast:

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
                                     const_cast<char **>(kwlist), &get, &set, &del, &doc))

    Annoying, yet more correct than before, and your code maintains type correctness. You just cast away the correct constness for the brain damaged external routine.

dereferencing type-punned pointer will break strict-aliasing rules

By default this warning is active when strict-aliasing optimizations are performed. It tries to let you know that you are asking the compiler to do undefined behavior and it may not do what you think it will do. As the optimization level increases, the likelihood that you won't like what it does will increase. I show a simple example later that surprisingly generates the wrong result when optimization at any level is turned on. Ignore this warning at your own peril. You are unlikely to care for the undefined behavior that results.

From the C++ Standard, section [basic.lval]/11

If a program attempts to access the stored value of an object through a glvalue whose type is not similar ([conv.qual]) to one of the following types the behavior is undefined:

  • the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to the dynamic type of the object, or
  • a char, unsigned char, or std::byte type.

If a program invokes a defaulted copy/move constructor or copy/move assignment operator for a union of type U with a glvalue argument that does not denote an object of type cv U within its lifetime, the behavior is undefined. [ Note: Unlike in C, C++ has no accesses of class type. — end note ]

  • -Wstrict-aliasing - equivalent to -Wstring-aliasing=3 (included in -Wall)
  • -Wstrict-aliasing=N where N is a level in {1,2,3} - Higher level implies less false positives, at the expense of more work.
    • Level 1: Most agressive, quick, very few false negatives, but many false positives. Might use if higher levels don't warn, but turning on -fstrict-aliasing breaks the code. Warns about pointer conversions even if pointer not dereferenced.
    • Level 2: Aggressive, quick, not too precise. Less false positives than Level 1, but more false negatives. Only warns if pointer is dereferenced.
    • Level 3: Very few false positives and very few false negatives — the default.
  • -fstrict-aliasing - also turned on by -O2, -O3 and -Os. Tells the compiler that it's ok to do a certain class of optimization based on the type of expressions. In particular you're promising by using this flag that an object of one type won't reside at the same address as an object of an incompatible type.
  • -fno-strict-aliasing - turns off this optimization. If this changes the behavior of your code, you have a problem in your code.

The following program generates 6 warnings about breaking strict-aliasing rules, and many would dismiss them. The correct output of the program is:

00000020 00200000

but when optimization is turned on it's:

00000020 00000020

THAT's what the warning is trying to tell you, that the optimizer is going to do things that you don't like. In this case seeing that acopy is set to a and never touched again, strict aliasing lets it optimize by just returning the original value of a at the end.

Broken version

uint32_t
swaphalves(uint32_t a)
{
    uint32_t acopy=a;
    uint16_t *ptr=(uint16_t*)&acopy;// can't use static_cast<>, not legal.
                                    // you should be warned by that.
    uint16_t tmp=ptr[0];
    ptr[0]=ptr[1];
    ptr[1]=tmp;
    return acopy;
}

int main()
{
    uint32_t a;
    a=32;
    cout << hex << setfill('0') << setw(8) << a << endl;
    a=swaphalves(a);
    cout << setw(8) << a << endl;
}

So what goes wrong? Since a uint16_t can't alias a uint32_t, under the rules, it's ignored in considering what to do with acopy. Since it sees that nothing is done with acopy inside the swaphalves function, it just returns the original value of a.

Here's the (annotated) x86 assembler generated by gcc 4.4.1 for swaphalves, let's see what went wrong:

_Z10swaphalvesj:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $16, %esp
    movl    8(%ebp), %eax   # get a in %eax
    movl    %eax, -8(%ebp)  # and store in in acopy
    leal    -8(%ebp), %eax  # now get eax pointing at acopy (ptr=&acopy)
    movl    %eax, -12(%ebp) # save that ptr at -12(%ebp)
    movl    -12(%ebp), %eax # get the ptr back in %eax
    movzwl  (%eax), %eax    # get 16 bits from ptr[0] in eax
    movw    %ax, -2(%ebp)   # store the 16 bits into tmp
    movl    -12(%ebp), %eax # get the ptr back in eax
    addl    $2, %eax        # bump up by two to get to ptr[1]
    movzwl  (%eax), %edx    # get that 16 bits into %edx
    movl    -12(%ebp), %eax # get ptr into eax
    movw    %dx, (%eax)     # store the 16 bits into ptr[1]
    movl    -12(%ebp), %eax # get the ptr again
    leal    2(%eax), %edx   # get the address of ptr[1] into edx
    movzwl  -2(%ebp), %eax  # get tmp into eax
    movw    %ax, (%edx)     # store into ptr[1]
    movl    -8(%ebp), %eax  # forget all that, return original a.
    leave
    ret

Scary, isn't it? Of course, if you are using gcc, you could use -fno-strict-aliasing to get the right output, but the generated code won't be as good. A better way to accomplish the same thing without the warnings or the incorrect output is to define swaphalves like this. N.B. this is supported in C99 and later C specs, as noted in this footnote to 6.5.2.3 Structure and union members:

If the member used to access the contents of a union object is not the
same as the member last used to store a value in the object, the appropriate
part of the object representation of the value is reinterpreted as an object
representation in the new type as described in 6.2.6 (a process sometimes
called ‘‘type punning’’). This might be a trap representation.

but your mileage may vary in C++, almost all compilers support it, but the spec doesn't allow it. Right after this discussion I'll have another solution with memcpy that may be slightly less efficient, (but probably not), and is supported by both C and C++):

Union version. Fixed for C but not guaranteed portable to C++

uint32_t
swaphalves(uint32_t a)
{
    typedef union {
        uint32_t as32bit;
        uint16_t as16bit[2];
    } swapem;

    swapem s={a};
    uint16_t tmp;
    tmp=s.as16bit[0];
    s.as16bit[0]=s.as16bit[1];
    s.as16bit[1]=tmp;
    return s.as32bit;
}

The C++ compiler knows that members of a union alias, and this helps the compiler generate MUCH better code:

_Z10swaphalvesj:
    pushl   %ebp                # save the original value of ebp
    movl    %esp, %ebp          # point ebp at the stack frame
    movl    8(%ebp), %eax       # get a in eax
    popl    %ebp                # get the original ebp value back
    roll    $16, %eax           # swap the two halves of a and return it
    ret

So do it wrong, via strange casts and get incorrect code, or by turning off strict-aliasing get inefficient code, or do it right and get efficient code.

You can also accomplish the same thing by using memcpy with char* to move the data around for the swap, and it will probably be as efficient. Wait, you ask me, how can that be? The will be at least to calls to memcpy added to the mix! Well gcc and other modern compilers have smart optimizers and will, in many cases, (including this one), elide the calls to memcpy. That makes it the most portable, and as efficient as any other method. Here's how it would look:

memcpy version, compliant to C and C++ specs and efficient

uint32_t
swaphalves(uint32_t a)
{
    uint16_t as16bit[2],tmp;

    memcpy(as16bit, &a, sizeof(a));
    tmp = as16bit[0];
    as16bit[0] = as16bit[1];
    as16bit[1] = tmp;
    memcpy(&a, as16bit, sizeof(a));
    return a;
}

For the above code, a C compiler will generate code similar to the previous solution, but with the addition of two calls to memcpy (possibly optimized out). GCC generates code identical to the previous solution. You can imagine other variants that substitute reading and writing through a char pointer locally for the calls to memcpy.

Suppressing Warnings in GCC

With GCC there are a couple of options when you want to supress warnings. First, beginning with version 3.1, since GCC won't report warnings for files that GCC considers ''system'' files, you can make GCC consider the problematic files system files. This is heavy handed, makes it easy for problems to creep in unnoticed, but effective. Second, beginning with version 4.2, you can suppress a particular class of warning either for an entire file, or (beginning at version 4.6), for a section of a file.

Supressing Warnings For A File By Making GCC See It As A System Header

Using a pragma to make GCC think a file or part of a file is a system header

Beginning with GCC 3.1, for a particular file, you can turn off all warnings including most warnings generated by the expansion of macros specified in a file by putting the following in a file

#pragma GCC system_header // File considered a system header.

It can be specified anywhere in the file, and code that precedes the pragma in the file will be unaffected. The intent of declaring a file a system header, is for operating system specific code that can't be strictly conforming C or C++. This should not be seen as a handy way of turning off bothersome warnings. Many (''most?'') warnings point to real issues and should be dealt with appropriately.

However, if you are using some extension that is supported by almost all today compilers (like -Wvariadic-macros which is C99/C++11 feature, but supported by almost all C++03 compilers), or used only when available (conditionally turned on) — it could be the only option and is fine to proceed, but the commentary is required.

Using -i to make GCC think all files in a directory are system headers

You can also turn off warnings for all files in a directory, by putting the directory into the include search path with -i instead of -I

The -idirectoryName command line option adds its argument to the list of directories to search for headers, just like -I. Any headers found in that directory will be considered system headers. It also has the side effect of changing the inclusion order, in that all files included from directories specified with -i are included ''after'' files included from directories specified via -I. If the directory is specified with both -I and -i it is still only searched after normal includes as part of the system include directories. This may be appropriate if you have to deal with other's spotty code that generates a lot of warnings that you can't fix.

If you turn off warnings for files that are shared with your users, you need to be able to see the warnings yourself so that as new problems arise you will see them. You can turn on warnings back on for system headers when you compile with -Wsystem-headers

This makes GCC print warning messages for constructs found in system header files that would normally not be seen. Using -Wall in conjunction with this option will not warn about unknown pragmas in system headers. For that, -Wunknown-pragmas must also be used.

Turning off warnings locally with GCC

So. Suppose you are getting a warning and have checked the code and are ''sure'' that it's a spurious warning. There's nothing wrong. ''If'' the warning is controllable via a command line -W option, then you can (if you have GCC version ''4.2'' or newer) turn it off temporarily. First you need to find out what the option might be, then if it exists turn it off via a pragma. How you do this varies a bit with GCC version. ===== Finding out what option controls the warning -fdiagnostics-show-option:: In GCC, for versions 4.2 and higher, this option instructs the diagnostic machinery to add text to each diagnostic emitted, which indicates which command line option directly controls that diagnostic, when such an option is known to the diagnostic machinery. The added text will look similar to [-Wsign-compare]. If you see this, that tells you that the -Wsign-compare command line option turns this warning on.

Turning the warnings off and on

I want to particularly thank Jonathan Wakely for his willingness to help and for the great help he offered on the gcc-help mailing list. It's people like him that make open source work. Without his help it would have taken me much longer to write this section. Any problems of course are my fault;) In addition to picking Jonathan's brain, I read the appropriate source in diagnostics.c and perused many releases of GCC documentation to get this information.

GCC provides the following pragmas to control warnings.

#pragma GCC diagnostic push

Available since GCC version 4.6, this pragma lets you remember diagnostic options in place at a particular time. This pragma can occur on any line of a file. The number of nested pushes is limited only by the size of memory and the size of an int index into the diagnostic information.

#pragma GCC diagnostic pop

Available since GCC version 4.6, this pragma lets you restore diagnostic options that were remembered by a diagnostic push. This pragma can occur on any line of a file. The number of pops is limited by memory and the size of an int index into the diagnostic information. At a pop information is moved from the table used by push into a history. An unbalanced pop, i.e. popping when nothing is on the stack is harmless and will simply reassert the user's command line diagnostic choices. Be careful, though, that you don't pop to soon. In this example:

foo()
{
    int unused,i;
    i=3;
}

We might want to suppress the unused variable like this:

foo()
{
#pragma GCC diagnostic push
#pragma GCC diagnostic "-Wunused-variable"
    int unused,i;
#pragma GCC diagnostic pop
    i=3;
}

and then be surprised that we still get a warning about an unused variable. The reason is, that GCC doesn't know the variable is unused until it hits the closing brace. That means the pop has to come after the closing brace:

foo()
{
#pragma GCC diagnostic push
#pragma GCC diagnostic "-Wunused-variable"
    int unused,i;
    i=3;
}
#pragma GCC diagnostic pop

#pragma GCC diagnostic [warning|error|ignored] OPTION:: From GCC version 4.2.4 and before GCC version 4.6 this could be specified at file scope outside of any functions, classes, unions, structs, or methods, to change the behavior when a particular class of error was seen. For GCC version 4.6 and later, it can be put in any line of a file, and affects from that position forward. For any supported version, it only works with warnings that have explicit -W arguments, use -fdiagnostic-show-option to find out which one to use. An example: #pragma GCC diagnostic ignored "-Wdeprecated-declarations"

====== version 4.2. You can turn them off but then what? So starting from 4.2 but before 4.6, just put near the top of the file something like:

#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

to turn off warnings from that point forward in the file of the use of deprecated declarations. Problematically, you have no way of knowing what the user had this option set to. They might have already had the warnings turned on, they might have had them set to ignore, or they might have had them set to cause an error. At the end of the file, if you do nothing else, the diagnostic for deprecated declarations stays ignored for anything that includes your file. You can set them to ignored, error, or warning at the end of the file before exiting, but you don't know which to use. This is sure to cause angst. ====== version 4.6 Now you can restore the user's flags For version 4.6 or later, you can save the state of the user's diagnostic flags.

See [http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html]

You can insert this around the line that causes the spurious warning:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

// Next you would have any amount of code for which you'd like to suppress that warning

#pragma GCC diagnostic pop

Of course this could cover everything from a line up to the whole file, and in between the push and the pop you could make multiple changes to each of multiple options.

== ====== == A handy macro to help you do some of this

Jonathan Wakely came up with a nice macro set to control this and I'm sharing a slightly modified version of it with you. It defines: GCC_DIAG_OFF(FLAG):: For versions 4.2-4.5 will turn warnings off for a particular error if controllable via a -W command line flag. If -fdiagostics-show-option told you that the warning was controlled by [-Wsign-compare], then you could say GCC_DIAG_OFF(sign_compare). Beginning at version 4.6, it will push the current state of the diagnostic flags and then turning warning off. Prior to version 4.2 it has no effect. GCC_DIAG_ON(FLAG):: For versions 4.2-4.5 will arbitrarily turn warnings on. This may not be what the user wanted. Beginning at version 4.6 it will simply pop the saved diagnostic stack. Prior to version 4.2 it has no effect.

Both of them should be used only at file scope for versions 4.2-4.5. Beginning at version 4.6 they can be used at any scope. If you want to turn multiple things from warning to error to ignored between the push and the pop then this will not be effective for you.

It allows you to do things like (for GCC version 4.6 or later):

    GCC_DIAG_OFF(sign-compare);
    if(a < b){
    GCC_DIAG_ON(sign-compare);

to turn off warnings that you know are spurious. (Probably a cast of one to the other's type or changing the declaration of the type of one to the other's would be a better fix.)

#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
#define GCC_DIAG_STR(s) #s
#define GCC_DIAG_JOINSTR(x,y) GCC_DIAG_STR(x ## y)
# define GCC_DIAG_DO_PRAGMA(x) _Pragma (#x)
# define GCC_DIAG_PRAGMA(x) GCC_DIAG_DO_PRAGMA(GCC diagnostic x)
# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
#  define GCC_DIAG_OFF(x) GCC_DIAG_PRAGMA(push) \
          GCC_DIAG_PRAGMA(ignored GCC_DIAG_JOINSTR(-W,x))
#  define GCC_DIAG_ON(x) GCC_DIAG_PRAGMA(pop)
# else
#  define GCC_DIAG_OFF(x) GCC_DIAG_PRAGMA(ignored GCC_DIAG_JOINSTR(-W,x))
#  define GCC_DIAG_ON(x)  GCC_DIAG_PRAGMA(warning GCC_DIAG_JOINSTR(-W,x))
# endif
#else
# define GCC_DIAG_OFF(x)
# define GCC_DIAG_ON(x)
#endif

These macro names won't collide with GCC macros since theirs start with one or two underscores.

A list of GCC common predefined macros.

Clang

TODO: __has_warning macro.

Clang tries to be an inplace GCC and MSVC replacement, pretending for your code as GCC (defines __GNUC__ macro) and MSVC (defines _MSC_VER macro), and supports most of their command line options (including warnings, however it might be doing just nothing). Please study a short but useful information in Clang documentation controlling errors and warnings.

The GCC-like -Wall, -Wextra, and -Wpedantic warnings groups are present (MSVC-like /W1../W4 too), and will enable nearly all warnings, a good start and a guide to eliminate warnings by recoding as far as possible.

However, it may still be necessary to suppress those that are not providing any useful guidance and cannot be reasonably eliminated.

Many of the method discussed above for GCC should be useful.

To ignore via a command line, to an option like -Wunused-variable add a preceeding no- thus: -Wno-unused-variable.

In a b2/bjam jamfile.v2, add, for example:

<toolset>clang:<cxxflags>-Wno-reorder
<toolset>clang:<cxxflags>-Wno-unused-variable
<toolset>clang:<cxxflags>-Wno-maybe-uninitialized

Clang also supports suppressing warnings by pragmas, see diagnostic pragams, for example:

#pragma clang diagnostic ignored "-Wno-unused-variable"

In addition to all of the functionality provided by GCC’s pragma, Clang also allows you to push and pop the current warning state. This is particularly useful when writing a header file that will be compiled by other people, because you don’t know what warning flags they build with.

As with MSVC and GCC, it is desirable to localize warning suppression by bracketing push'n'pop pragmas. Localization is especially important in all included .hpp library files to avoid quietly suppressing warnings in user code: the user may need to see warnings in his code. A contrived example is:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmultichar"

char b = 'df'; // Avoid a warning that more than one chars are provided.

#pragma clang diagnostic pop

But this is not fully portable and will produce 'unrecognized pragmas' on some other platforms.

Macros that allow this to be done without causing complaint from other compilers is

#ifdef __clang__
#  define CLANG_DIAG_STR(s) # s
// stringize s to "no-unused-variable"
#  define CLANG_DIAG_JOINSTR(x,y) CLANG_DIAG_STR(x ## y)
//  join -W with no-unused-variable to "-Wno-unused-variable"
#  define CLANG_DIAG_DO_PRAGMA(x) _Pragma (#x)
// _Pragma is unary operator  #pragma ("")
#  define CLANG_DIAG_PRAGMA(x) CLANG_DIAG_DO_PRAGMA(clang diagnostic x)
#    define CLANG_DIAG_OFF(x) CLANG_DIAG_PRAGMA(push) \
          CLANG_DIAG_PRAGMA(ignored CLANG_DIAG_JOINSTR(-W,x))
// For example: #pragma clang diagnostic ignored "-Wno-unused-variable"
#   define CLANG_DIAG_ON(x) CLANG_DIAG_PRAGMA(pop)
// For example: #pragma clang diagnostic warning "-Wno-unused-variable"
#else // Ensure these macros so nothing for other compilers.
#  define CLANG_DIAG_OFF(x)
#  define CLANG_DIAG_ON(x)
#  define CLANG_DIAG_PRAGMA(x)
#endif

/* Usage:
  CLANG_DIAG_OFF(unused-variable)
  CLANG_DIAG_OFF(unused-parameter)
  CLANG_DIAG_OFF(uninitialized)
 */
#include <iostream>
#include <boost/assert.hpp>

int main()
{
  #ifdef __clang__
  std::cout 
    << "Clang "<< __clang_major__ << '.' << __clang_minor__<< '.' << __clang_patchlevel__ 
    << std::endl;
  #endif

// Clang method of saving and restoring current warning state.
  #pragma clang diagnostic push
  #pragma clang diagnostic pop

// Example of using Clang push'n'pop around two ignored warnings.
  #pragma clang diagnostic push
  #pragma clang diagnostic ignored "-Wmultichar"
  #pragma clang diagnostic ignored "-Wconstant-conversion"
  #pragma clang diagnostic ignored  "-Wunused-variable"
  char b = 'df'; // Most unwisely ignoring ALL warnings.
  #pragma clang diagnostic pop

// Example of using macro for push and pop pragmas.
  CLANG_DIAG_PRAGMA(push);
  #pragma clang diagnostic ignored "-Wunused-variable"
  int unused;
  CLANG_DIAG_PRAGMA(pop);

  // example of using macro to push warning state,suppress a warning and restore state.
  CLANG_DIAG_OFF(unused-variable)
  int unused_two;  // No warning from unused variable.
  CLANG_DIAG_ON(unused-variable) //

  int unused_too; // Expect an unused-variable warning!

  return 0;
}

Output is:

Clang 3.1.0

 clang++.exe -dD -Wall -Wextra   -c -g -Wall 
  -I/i/boost-trunk -MMD -MP -MF build/Debug/MinGW_Clang-Windows/warnings_1.o.d 
  -o build/Debug/MinGW_Clang-Windows/warnings_1.o warnings_1.cpp
warnings_1.cpp:97:7: warning: unused variable 'unused_too' [-Wunused-variable]
  int unused_too; // Expect an unused-variable warning!
      ^
1 warning generated.

but for MSVC

 ClCompile:
  warning_1.cpp
warning_1.cpp(77): warning C4068: unknown pragma
warning_1.cpp(78): warning C4068: unknown pragma
warning_1.cpp(81): warning C4068: unknown pragma
warning_1.cpp(82): warning C4068: unknown pragma
warning_1.cpp(83): warning C4068: unknown pragma
warning_1.cpp(84): warning C4068: unknown pragma
warning_1.cpp(85): warning C4305: 'initializing' : truncation from 'int' to 'char'
warning_1.cpp(85): warning C4309: 'initializing' : truncation of constant value
warning_1.cpp(86): warning C4068: unknown pragma
warning_1.cpp(90): warning C4068: unknown pragma
warning_1.cpp(99): warning C4101: 'unused_too' : unreferenced local variable
warning_1.cpp(96): warning C4101: 'unused_two' : unreferenced local variable
warning_1.cpp(85): warning C4189: 'b' : local variable is initialized but not referenced
warning_1.cpp(91): warning C4101: 'unused' : unreferenced local variable
j:\cpp\svg\warning_1\warning_1.cpp(66): warning C4701: potentially uninitialized local variable 'x' used

All this shows that eliminating warnings is usually much less trouble, and more important, is much clearer and uncluttered.

Intel

Information needed here.

Darwin/MacOS

Information needed here.

ACC

Information needed here.

Borland

Information needed here.

Sun

Sun compiler some Sun workarounds to some Sun compiler errors/warnings.

Other C++ Language tools

There are, of course, many other bug/bad-feature finding tools.

TODO lots more examples?

  1. cppCheck is an analysis tool for C/C++ code. Unlike C/C++ compilers and many other analysis tools, it doesn't detect syntax errors. Cppcheck only detects the types of bugs that the compilers normally fail to detect. The goal is no false positives. There is a list of checks performed.

  2. USBSan Undefined Behavior Sanitizer

  3. cppLint

  4. TODO

Copyright Paul A. Bristow 2019. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).