Help the compiler help you

Foreword


Modern compilers have a huge number of diagnostics. And surprisingly, very few of them are enabled by default.


A huge number of claims that are presented to the C ++ language on these your Internet sites - about complexity, insecurity, shooting on the legs, etc. - refer precisely to those cases when people simply do not know that these problems can be solved Flick of your finger on the keyboard.


Let's fix this flagrant injustice and shed the light of truth on the compiler's ability to prevent errors.



Content


  1. Ode to the compiler
  2. Ignore cannot be fixed
  3. -Wall
  4. -Wextra
  5. -Wpedantic
  6. Need More Warnings
  7. -Werror
  8. Conclusion
  9. References


Ode to the compiler


The compiler is the best friend of the plus. A compiler is not just a translator of a formal human-readable language into machine codes. The compiler is the best helper in writing programs.


An important (and not the only) help provided by the compiler is the search for errors. And I'm not talking about typos, type mismatch, and other syntax errors. I am talking about a huge set of errors that can be caught using the warning mechanism.


, , , , , "" .. , .




β€” "" , . β€” . β€” , , , , - .


, . , , , . , , . static_cast , , .


, .


, .


, C++ GCC (, Clang). .


-Wall


-Wall β€” "" . C++ , ( , , , ).


:

, , .



-Waddress


. , . , :


bool func () {return false;}

int main ()
{
    if (func)
    {
        return 1;
    }
}

prog.cc: In function 'int main()':
prog.cc:5:9: warning: the address of 'bool func()' will never be NULL [-Waddress]
    5 |     if (func)
      |         ^~~~

β€” . , , :


int main ()
{
    const char * a = "abc";
    if (a == "abc")
    {
        return 0;
    }
}

:


prog.cc: In function 'int main()':
prog.cc:4:11: warning: comparison with string literal results in unspecified behavior [-Waddress]
    4 |     if (a == "abc")
      |         ~~^~~~~~~~


-Warray-bounds=1


. -O2.


int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    return a[5];
}

prog.cc: In function 'int main()':
prog.cc:4:15: warning: array subscript 5 is above array bounds of 'int [5]' [-Warray-bounds]
    4 |     return a[5];
      |            ~~~^
prog.cc:3:9: note: while referencing 'a'
    3 |     int a[5] = {1, 2, 3, 4, 5};
      |         ^


-Wbool-compare


, :


int main ()
{
    int n = 5;

    if ((n > 1) == 2)
    {
        return 0;
    }
}

prog.cc: In function 'int main()':
prog.cc:5:17: warning: comparison of constant '2' with boolean expression is always false [-Wbool-compare]
    5 |     if ((n > 1) == 2)
      |         ~~~~~~~~^~~~


-Wbool-operation


. , :


int main ()
{
    bool b = true;
    auto c = ~b;
}

prog.cc: In function 'int main()':
prog.cc:4:15: warning: '~' on an expression of type 'bool' [-Wbool-operation]
    4 |     auto c = ~b;
      |               ^
prog.cc:4:15: note: did you mean to use logical not ('!')?

, C++17 , .



-Wcatch-value


, :


struct A
{
    virtual ~A () {};
};

struct B: A{};

int main ()
{
    try {}
    catch (A) {}
}

prog.cc: In function 'int main()':
prog.cc:11:12: warning: catching polymorphic type 'struct A' by value [-Wcatch-value=]
   11 |     catch (A) {}
      |            ^

: -Wcatch-value=n (. ).



-Wchar-subscripts


, char. char :


int main ()
{
    int a[] = {1, 2, 3, 4};
    char index = 'a' - 'b';
    return a[index];
}

prog.cc: In function 'int main()':
prog.cc:5:14: warning: array subscript has type 'char' [-Wchar-subscripts]
    5 |     return a[index];
      |              ^~~~~


-Wcomment


, (/*), , .


int main ()
{
    /* asd /* fgh */
    //qwe\
    rty
}

prog.cc:3:8: warning: "/*" within comment [-Wcomment]
    3 |     /* /* */
      |
prog.cc:4:5: warning: multi-line comment [-Wcomment]
    4 |     //ssd\
      |     ^


-Wint-in-bool-context


, , , :


int main ()
{
    int a = 5;
    if (a <= 4 ? 2 : 3)
    {
        return 0;
    }
}

prog.cc: In function 'int main()':
prog.cc:4:16: warning: ?: using integer constants in boolean context, the expression will always evaluate to 'true' [-Wint-in-bool-context]
    4 |     if (a <= 4 ? 2 : 3)
      |         ~~~~~~~^~~~~~~

β€” . , , , :


int main ()
{
    for (auto a = 0; 1 << a; a++);
}

prog.cc: In function 'int main()':
prog.cc:3:24: warning: '<<' in boolean context, did you mean '<' ? [-Wint-in-bool-context]
    3 |     for (auto a = 0; 1 << a; a++);
      |                      ~~^~~~

.


int main ()
{
    int a = 5;
    if (a * 5);
}

prog.cc: In function 'int main()':
prog.cc:4:11: warning: '*' in boolean context, suggest '&&' instead [-Wint-in-bool-context]
    4 |     if (a * 5);
      |         ~~^~~


-Winit-self


. -Wuninitialized.


int main ()
{
    int i = i;
    return i;
}

prog.cc: In function 'int main()':
prog.cc:3:9: warning: 'i' is used uninitialized in this function [-Wuninitialized]
    3 |     int i = i;
      |         ^


-Wlogical-not-parentheses


. , .


, :


int main ()
{
    int a = 9;
    if (!a > 1);
}

prog.cc: In function 'int main()':
prog.cc:5:12: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses]
    5 |     if (!a > 1);
      |            ^
prog.cc:5:9: note: add parentheses around left hand side expression to silence this warning
    5 |     if (!a > 1);
      |         ^~
      |         ( )

, β€” , .



-Wmaybe-uninitialized


, .


int main (int argc, const char * argv[])
{
    int x;
    switch (argc)
    {
        case 1: x = 1;
            break;
        case 2: x = 4;
            break;
        case 3: x = 5;
    }
    return x;
}

prog.cc: In function 'int main(int, const char**)':
prog.cc:3:9: warning: 'x' may be used uninitialized in this function [-Wmaybe-uninitialized]
    3 |     int x;
      |         ^

default:


int main (int argc, const char * argv[])
{
    int x;
    switch (argc)
    {
        case 1: x = 1;
            break;
        case 2: x = 4;
            break;
        case 3: x = 5;
            break;
        default:
            x = 17;
    }
    return x;
}


-Wmemset-elt-size


memset, β€” , β€” , , .


#include <cstring>

int main ()
{
    constexpr auto size = 20ul;
    int a[size];
    std::memset(a, 0, size);
}

prog.cc: In function 'int main()':
prog.cc:7:27: warning: 'memset' used with length equal to number of elements without multiplication by element size [-Wmemset-elt-size]
    7 |     std::memset(a, 0, size);
      |                           ^


-Wmemset-transposed-args


, , , memset:


#include <cstring>

int main ()
{
    constexpr auto size = 20ul;
    int a[size];
    std::memset(a, size, 0);
}

prog.cc: In function 'int main()':
prog.cc:7:27: warning: 'memset' used with constant zero length parameter; this could be due to transposed parameters [-Wmemset-transposed-args]
    7 |     std::memset(a, size, 0);
      |                           ^


-Wmisleading-indentation


, . if, else, while for. :


int main ()
{
    int x;
    if (true)
        x = 3;
        return x;
}

prog.cc: In function 'int main()':
prog.cc:4:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
    4 |     if (true)
      |     ^~
prog.cc:6:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    6 |         return x;
      |         ^~~~~~

. -Wempty-body.



-Wmissing-attributes


, , .


template <class T>
T* __attribute__ ((malloc, alloc_size (1)))
foo (long);

template <>
void* __attribute__ ((malloc))
foo<void> (long);

int main ()
{
}

prog.cc:7:1: warning: explicit specialization 'T* foo(long int) [with T = void]' may be missing attributes [-Wmissing-attributes]
    7 | foo<void> (long);
      | ^~~~~~~~~
prog.cc:3:1: note: missing primary template attribute 'alloc_size'
    3 | foo (long);
      | ^~~


-Wmultistatement-macros


, , if, else, while for. , , , :


#define INCREMENT x++; y++

int main ()
{
    int x = 0;
    int y = 0;
    if (true)
        INCREMENT;
}

prog.cc: In function 'int main()':
prog.cc:1:19: warning: macro expands to multiple statements [-Wmultistatement-macros]
    1 | #define INCREMENT x++; y++
      |                   ^
prog.cc:8:9: note: in expansion of macro 'INCREMENT'
    8 |         INCREMENT;
      |         ^~~~~~~~~
prog.cc:7:5: note: some parts of macro expansion are not guarded by this 'if' clause
    7 |     if (true)
      |     ^~

. -Wmisleading-indentation.



-Wnonnull


, nonnull.


void f (int * ptr) __attribute__((nonnull));

int main ()
{
    f(nullptr);
}

void f (int *) {}

prog.cc: In function 'int main()':
prog.cc:5:14: warning: null argument where non-null required (argument 1) [-Wnonnull]
    5 |     f(nullptr);
      |              ^


-Wnonnull-compare


, nonnull.


bool f (int * ptr) __attribute__((nonnull));

int main ()
{
    f(nullptr);
}

bool f (int * p)
{
    return p == nullptr;
}

prog.cc: In function 'bool f(int*)':
prog.cc:10:17: warning: nonnull argument 'p' compared to NULL [-Wnonnull-compare]
   10 |     return p == nullptr;
      |                 ^~~~~~~


-Wparentheses


β€” , :


int main ()
{
    int x = 5;
    if (x = 4)
    {
        x = 3;
    }
}

, , :


prog.cc: In function 'int main()':
prog.cc:4:11: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
    4 |     if (x = 4)
      |         ~~^~~

, , :


int main ()
{
    int x = 5;
    if ((x = 4))
    {
        x = 3;
    }
}


-Wpessimizing-move


. :


#include <utility>

struct A {};

A f ()
{
    A a;
    return std::move(a);
}

int main ()
{
    f();
}

prog.cc: In function 'A f()':
prog.cc:8:21: warning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move]
    8 |     return std::move(a);
      |            ~~~~~~~~~^~~
prog.cc:8:21: note: remove 'std::move' call


-Wreorder


, . , .


struct A
{
    int i;
    int j;

    A(): j(0), i(1)
    {
    }
};

int main () {}

prog.cc: In constructor 'A::A()':
prog.cc:4:9: warning: 'A::j' will be initialized after [-Wreorder]
    4 |     int j;
      |         ^
prog.cc:3:9: warning:   'int A::i' [-Wreorder]
    3 |     int i;
      |         ^
prog.cc:6:5: warning:   when initialized here [-Wreorder]
    6 |     A(): j(0), i(1)
      |     ^


-Wreturn-type


, :


int f ()
{
}

int main () {}

prog.cc: In function 'int f()':
prog.cc:3:1: warning: no return statement in function returning non-void [-Wreturn-type]
    3 | }
      | ^


-Wsequence-point


. ( ):


int main ()
{
    int a = 6;
    ++a = a++;
}

prog.cc: In function 'int main()':
prog.cc:4:12: warning: operation on 'a' may be undefined [-Wsequence-point]
    4 |     ++a = a++;
      |           ~^~


-Wsign-compare


. , - . , :


int main ()
{
    short a = -5;
    unsigned b = 4;
    if (a < b)
    {
        return 0;
    }

    return 1;
}

prog.cc: In function 'int main()':
prog.cc:5:11: warning: comparison of integer expressions of different signedness: 'short int' and 'unsigned int' [-Wsign-compare]
    5 |     if (a < b)
      |         ~~^~~


-Wsizeof-pointer-div


sizeof, . , , :


int main ()
{
    const char * a = "12345";
    auto size = sizeof (a) / sizeof (a[0]);
}

prog.cc: In function 'int main()':
prog.cc:4:28: warning: division 'sizeof (const char*) / sizeof (const char)' does not compute the number of array elements [-Wsizeof-pointer-div]
    4 |     auto size = sizeof (a) / sizeof (a[0]);
      |                 ~~~~~~~~~~~^~~~~~~~~~~~~~~
prog.cc:3:18: note: first 'sizeof' operand was declared here
    3 |     const char * a = "12345";
      |                  ^


-Wsizeof-pointer-memaccess


, (str..., mem... ..), sizeof. :


#include <cstring>

int main ()
{
    char a[10];
    const char * s = "qwerty";
    std::memcpy (a, s, sizeof(s));
}

prog.cc: In function 'int main()':
prog.cc:7:24: warning: argument to 'sizeof' in 'void* memcpy(void*, const void*, size_t)' call is the same expression as the source; did you mean to provide an explicit length? [-Wsizeof-pointer-memaccess]
    7 |     std::memcpy (a, s, sizeof(s));
      |                        ^~~~~~~~~


-Wstrict-aliasing


(strict aliasing) β€” . .


, .



-Wswitch


, switch:


enum struct enum_t
{
    a, b, c
};

int main ()
{
    enum_t e = enum_t::a;
    switch (e)
    {
        case enum_t::a:
        case enum_t::b:
            return 0;
    }
}

prog.cc: In function 'int main()':
prog.cc:9:12: warning: enumeration value 'c' not handled in switch [-Wswitch]
    9 |     switch (e)
      |            ^


-Wtautological-compare


:


int main ()
{
    int i = 1;
    if (i > i);
}

prog.cc: In function 'int main()':
prog.cc:4:11: warning: self-comparison always evaluates to false [-Wtautological-compare]
    4 |     if (i > i);
      |         ~ ^ ~

, , ( ):


int main ()
{
    int i = 1;
    if ((i & 16) == 10);
}

prog.cc: In function 'int main()':
prog.cc:4:18: warning: bitwise comparison always evaluates to false [-Wtautological-compare]
    4 |     if ((i & 16) == 10);
      |         ~~~~~~~~ ^~ ~~


-Wtrigraphs


, . , , .


. -Wcomment.



-Wuninitialized


, :


int main ()
{
    int x;
    return x;
}

prog.cc: In function 'int main()':
prog.cc:4:12: warning: 'x' is used uninitialized in this function [-Wuninitialized]
    4 |     return x;
      |            ^


-Wunused-function


, , , , , inline, .



-Wunused-variable


, .


int main ()
{
    int x = 0;
}

prog.cc: In function 'int main()':
prog.cc:3:9: warning: unused variable 'x' [-Wunused-variable]
    3 |     int x = 0;
      |         ^

, , , static_cast<void>(...):


int main ()
{
    int x = 0;
    static_cast<void>(x);
}


-Wextra


"" . , -Wall ( -Wall, ).




-Wempty-body


do-while. , :


int main ()
{
    if (true);
    {
        return 1;
    }
}

prog.cc: In function 'int main()':
prog.cc:3:14: warning: suggest braces around empty body in an 'if' statement [-Wempty-body]
    3 |     if (true);
      |              ^

. -Wmisleading-indentation.



-Wimplicit-fallthrough


"" switch:


int main ()
{
    int x = 7;
    int a;
    switch (x)
    {
        case 1:
            a = 1;
            break;
        case 2:
            a = 2;
        case 3:
            a = 3;
            break;
        default:
            a = 0;
    }
    return a;
}

, break, case 2 :


prog.cc: In function 'int main()':
prog.cc:11:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
   11 |             a = 2;
      |             ~~^~~
prog.cc:13:9: note: here
   13 |         case 3:
      |         ^~~~

C++17 β€” fallthrough:


int main ()
{
    int x = 7;
    int a;
    switch (x)
    {
        case 1:
            a = 1;
            break;
        case 2:
            a = 2;
            [[fallthrough]];
        case 3:
            a = 3;
            break;
        default:
            a = 0;
    }
    return a;
}


-Wmissing-field-initializers


, . :


struct S
{
    int f;
    int g;
    int h;
};

int main ()
{
    S s{3, 4};
}

prog.cc: In function 'int main()':
prog.cc:10:13: warning: missing initializer for member 'S::h' [-Wmissing-field-initializers]
   10 |     S s{3, 4};
      |             ^


-Wredundant-move


std::move , , :


#include <utility>

struct S {};

S f (S s)
{
    return std::move(s);
}

int main ()
{
    auto s = f(S{});
}

prog.cc: In function 'S f(S)':
prog.cc:7:21: warning: redundant move in return statement [-Wredundant-move]
    7 |     return std::move(s);
      |            ~~~~~~~~~^~~
prog.cc:7:21: note: remove 'std::move' call


-Wtype-limits


, . , . , , , , , , . , - :


int main ()
{
    unsigned x = 17;
    if (x >= 0)
    {
        return 1;
    }
}

prog.cc: In function 'int main()':
prog.cc:4:11: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
    4 |     if (x >= 0)
      |         ~~^~~~


-Wshift-negative-value


. , :


int main ()
{
    const int x = -7;
    return x << 4;
}

prog.cc: In function 'int main()':
prog.cc:4:17: warning: left shift of negative value [-Wshift-negative-value]
    4 |     return x << 4;
      |                 ^


-Wunused-parameter


. , , .


void f (int x) {}

int main ()
{
}

prog.cc: In function 'void f(int)':
prog.cc:1:13: warning: unused parameter 'x' [-Wunused-parameter]
    1 | void f (int x) {}
      |         ~~~~^

C++17 maybe_unused:


void f ([[maybe_unused]] int x) {}

int main ()
{
}


-Wunused-but-set-parameter


, , . , :


void f (int x)
{
    x = 7;
}

int main ()
{
}

prog.cc: In function 'void f(int)':
prog.cc:1:13: warning: parameter 'x' set but not used [-Wunused-but-set-parameter]
    1 | void f (int x)
      |         ~~~~^


-Wpedantic


-Wall -Wextra β€” , .


-Wpedantic ( -pedantic), ISO C++, , , .




. , - "", .




-Wctor-dtor-privacy


, , , - .


class base
{
    base () {};
    ~base() {};
};

int main ()
{
}

prog.cc:1:7: warning: 'class base' only defines a private destructor and has no friends [-Wctor-dtor-privacy]
    1 | class base
      |       ^~~~

, , -, .



-Wnon-virtual-dtor


, -, . . , .


struct base
{
    virtual void f (int) {}
    ~base() {};
};

int main ()
{
}

prog.cc:1:8: warning: 'struct base' has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]
    1 | struct base
      |        ^~~~


-Wold-style-cast


C. static_cast, dynamic_cast, reinterpret_cast const_cast, . β€” , , β€” . .



-Woverloaded-virtual


- :


struct base
{
    virtual void f (int) {}
};

struct derived: base
{
    void f () {};
};

int main ()
{
}

prog.cc:3:18: warning: 'virtual void base::f(int)' was hidden [-Woverloaded-virtual]
    3 |     virtual void f (int) {}
      |                  ^
prog.cc:8:10: warning:   by 'void derived::f()' [-Woverloaded-virtual]
    8 |     void f () {};
      |          ^


-Wsign-promo


. :


void f (int) {}
void f (unsigned) {}

int main ()
{
    unsigned short x = 7;
    f(x);
}

prog.cc: In function 'int main()':
prog.cc:7:8: warning: passing 'short unsigned int' chooses 'int' over 'unsigned int' [-Wsign-promo]
    7 |     f(x);
      |        ^
prog.cc:7:8: warning:   in call to 'void f(int)' [-Wsign-promo]

, - , . - , .



-Wduplicated-branches


, if else :


int main ()
{
    if (true)
        return 0;
    else
        return 0;
}

prog.cc: In function 'int main()':
prog.cc:3:5: warning: this condition has identical branches [-Wduplicated-branches]
    3 |     if (true)
      |     ^~

?: :


int main ()
{
    auto x = true ? 4 : 4;
}

prog.cc: In function 'int main()':
prog.cc:3:19: warning: this condition has identical branches [-Wduplicated-branches]
    3 |     auto x = true ? 4 : 4;
      |              ~~~~~^~~~~~~

, , -Wall, .


. -Wduplicated-cond.



-Wduplicated-cond


if-else-if:


int main ()
{
    auto x = 6;
    if (x > 7) {return 0;}
    else if (x > 7) {return 1;}
}

prog.cc: In function 'int main()':
prog.cc:5:10: warning: duplicated 'if' condition [-Wduplicated-cond]
    5 |     else if (x > 7) {return 1;}
      |          ^~
prog.cc:4:5: note: previously used here
    4 |     if (x > 7) {return 0;}
      |     ^~

. -Wduplicated-branches.



-Wfloat-equal


. , , .


( , ), std::equal_to, .



-Wshadow=compatible-local


, , .



-Wcast-qual


, . , const.



-Wconversion


, , . ( ) , . :


int main ()
{
    double x = 4.5;
    int y = x;
}

prog.cc: In function 'int main()':
prog.cc:12:13: warning: conversion from 'double' to 'int' may change value [-Wfloat-conversion]
   12 |     int y = x;
      |             ^

, .



-Wzero-as-null-pointer-constant


nullptr.



-Wextra-semi


. -.



-Wsign-conversion


-Wconversion , :


int main ()
{
    signed si = -8;
    unsigned ui;
    ui = si;
}

prog.cc: In function 'int main()':
prog.cc:5:10: warning: conversion to 'unsigned int' from 'int' may change the sign of the result [-Wsign-conversion]
    5 |     ui = si;
      |          ^~


-Wlogical-op


. , "" "", :


int main ()
{
    int a = 8;
    if (a < 0 && a < 0)
    {
        return 1;
    }
}

prog.cc: In function 'int main()':
prog.cc:4:15: warning: logical 'and' of equal expressions [-Wlogical-op]
     if (a < 0 && a < 0)
         ~~~~~~^~~~~~~~


-Werror


, , . . .


. , β€” - , , .


-Werror -pedantic-errors, -Wpedantic -Werror.

, .



, GCC (Clang - , ) , .


-Werror
-pedantic-errors

-Wall
-Wextra
-Wpedantic

-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wduplicated-branches
-Wduplicated-cond
-Wextra-semi
-Wfloat-equal
-Wlogical-op
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wsign-conversion
-Wsign-promo

, , . . , β€” . , , . , , , .


.




  1. GCC
  2. Clang

All Articles