Compiler warnings in C ++: accept cannot be refused

    We once got into a conversation in Cloud4Y about programming in the cloud and about which programming language can rightfully be considered the most "cloudy". How long it took, they came to a discussion of the mistakes of the copywriters - about their twofold nature: you can’t ignore everything, and pay attention to everyone - you won’t move your mind for long. Today we will present you a small scenario of handling compiler warnings, which will allow you not to miss a gross error and keep the nervous system in order.


    image

    We often see compiler warnings about parts of the code that have potential problems or bad styles. Sometimes they point to code that really doesn't work, so don't ignore them.


    You probably saw one or two compiler warnings when compiling C ++ code . If you are working on a large-scale project, then you see hundreds of such warnings every day, and after a while some of them become familiar to you. You no longer just know them, they become the annoying background noise that comes up every time you start compiling.


    Do not ignore compiler warnings


    Of course, these warnings cannot but annoy; moreover, most often they arise for perfectly working code that definitely does not contain bugs.


    But be sure that one of several thousand compiler warnings really makes sense. Sometimes we write code that compiles, but  something does not work as we expected. So how, in the name of Habr, to determine which warning indicates a real error? How to distinguish it from hundreds of others for which the code is valid? Is it really necessary to spend so much time reading all of them? It is almost impossible.
    Accept the "no warning" policy


    To be completely honest, there are only two things you can do with compiler warnings — ignore them or get rid of them. Ignoring them means throwing a tool into the bin that will help prevent bugs. Do you agree to look through your fingers at the presence of one or two serious errors? Probably not.


    You can say that if there are only a few compiler warnings, you can live with it. Here's the thing: you probably check your code relatively often (at least we hope so). This means that you often have to compile, and this entails compiler warnings. You will begin to pay attention to them. You may still be paying attention to them if you receive 6 warnings instead of 5; but will you notice the  11th ? The 20th ? 52nd ?
    Getting rid of warnings is the only acceptable and safe option for the psyche.


    Change your code to get rid of warnings


    Although sometimes we want the compiler to simply keep silent about a specific warning, it’s better to just change the code. If the code is not clear to the compiler, then there is every chance that it will not be understandable to humans either.


    Clarifying your intentions in the code is often enough to silence the compiler. Some compilers may give a hint on how to resolve specific warnings. Let's take a look at the frequently occurring assignment warnings in a conditional context:


    image

    For Clang, it looks like this:


    image

    The second case that underlies this warning: sometimes we write a = b, when we meant a == b.


    While other compilers simply warn that the task we wrote looks rather strange in this section of code, CLANG helpfully tries to guess what we could mean.


    The first pointer simply tells us how to fix the warning if the task was actually intended. GCC has the same warning and suggestion to fix, but without providing an alternative:


    image

    Many prefer CLANG, as it allows us to guess what the correct solution is. This is much better, because it makes it possible to find a bug in the code, which would not happen, we automatically accept everything that the compiler offers.


    Even if an assignment really was planned, accepting a compiler sentence and adding a pair of brackets may not be the right solution.


    In terms of pure code, we must separate the assignment and the condition. It is much more convenient to have one line for each task, that is, in fact, apply the principle of single responsibility on a line-by-line basis:


    image

    Do not correct compiler warnings automatically; make corrections deliberately.
    Tell the compiler what types of warnings are important to you.


    There are several ways to work with the compiler and not receive warnings. Naturally, writing code that even the poor compiler understands is the best solution. However, there is also the opportunity to tell the compiler which warnings are of interest to you and which are not.


    Compiler flags


    Each compiler we know provides the ability to select the alerts you want to see. You can disable various alert groups, and sometimes you can reassign individual alerts to a different alert level. Typically, these features are provided as command line options in the IDE settings. This means that you can have a single place - preferably your build script - where you can apply these settings.


    What warning flags to use? This depends in part on the compiler, since different compilers emit different warnings, and some of them may be not just wrong, but crazy.


    Some warnings may be too pedantic for your taste or for your style of writing code, although we still have not come across warnings that have no basis. (In our opinion, it is generally better to look through all warnings so as not to miss the important).


    The standard flags for most warnings are Wall, Wpedantic, Wextra (many compiler flags related to warnings start with W).
    If you are just starting to apply the “no warnings” policy to your project, you will most likely receive hundreds or even thousands of warnings if they are all included. Start with a lower warning level. Record the hardest warnings and gradually build up your alert level.


    If you are prone to moments of laziness, or you have colleagues who oppose a “no warning” policy, then disabling them will not be so easy at all. In  someone may want to check the code that contains a warning. In the end, it turns out that this is not an error, the code compiles and will probably work as intended. Thus, a bunch of warnings will resolve, one after another.


    To avoid such a waste of time, you can strengthen the “no warnings” policy by switching warnings to errors. Thus, errors will be difficult to ignore - otherwise the build will simply fail. This can be done with individual warnings, as well as with all warnings at the same time. Set the corresponding -Werror flag for Clang and GCC and / WX for MSVC.


    Pragma Directives


    Compilers often use specific #pragma directives to enable or disable specific code warnings. These directives should be considered as a temporary solution because they have their drawbacks:


    • Disabling warnings with #pragma drowns out the compiler for the remaining unit. If you want to disable this warning only once, be sure to include it right after the line of code with the question. Enabling #pragma for the header file and deciding not to include warnings will again silence the compiler for each source that has a header, as well as for each header after #pragma
    • The #pragma warning directives are not portable. The identifiers for each individual warning vary for different compilers, as does the #pragma format. Sometimes compilers give warnings about unknown #pragma - and you definitely won't want to write a #pragma warning in the GCC that it should ignore these MSVC warnings. Enclosing them in #ifdefs is clearly not the best solution.

    There are times when using #pragma is not suitable for you.


    An example is the headers of third-party libraries that you cannot change, and the compiler complains about them. Another example is with a once written embeddable language: it used operator overloading in an unusual way that ignored the built-in priority of C ++ statements .


    The compiler helpfully suggested adding extra brackets. This might be the right decision if the operators were applicable to numeric values. In order for the DSL code to be read, in this case it is required to silence the warning without touching the code, disabling the warning with #pragma in combination with an explanatory comment will help here.


    Instead of a conclusion


    You can configure the compiler by letting it know which warnings are of interest to you and which are not; use command line arguments or, if necessary, the #pragmas directives. Try to be as strict as possible, do not add too many exceptions. This means careful use of #pragmas and deviations from your standard command line arguments.


    PS Sometimes none of the above methods is a realistic solution. Then just use the shut up command for the compiler.


    Also popular now: