Is it wise to ignore gcc/clang's “-Wmissing-br

2019-01-09 00:08发布

问题:

Consider the following program:

#include <array>

int main()
{
  std::array<int, 1> x = { 0 }; // warning!
  x = { { 0 } }; // no warning
  return 0;
}

The first initialization leads to warnings on gcc 4.7.2...

main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]

... and clang 3.1

main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
  std::array<int, 1> x = { 0 };

As far as the standard goes, there should be no difference between double or single curly braces, at least in this example.

There are two ways to deal with the warning:

  1. Just turn it off
  2. Fix the code, so the compiler is happy

What do you propose? IMHO, the double curly expression looks somewhat ugly. On the other hand, the warning might detect real problems in more complicated examples. Do you know an example where the warning would have helped you?

回答1:

-Wmissing-braces will no longer be enabled in GCC's -Wall (for C++ mode), as of 4.8, for precisely the reason you describe. For current versions of GCC, either disable or ignore the warning, the code you have is written the way it should be.

The warning is probably meant to cover code such as

struct A { int a; int b; };
struct B { A a; int b; };
B b = {
  1,
  2 // initialises b.a.b, not b.b
};

However, IMHO, that is already handled well enough by -Wmissing-field-initializers, which does not warn about your original code.



回答2:

I get the same warning in Xcode 6.1.1 (the current version as of March 9, 2015). When I add the extra braces around each subobject I get an error. When I add an extra set of braces around the entire initialization list then the warning goes away. According to the standard specification 14882:2011 23.3.2.1 [array.overview] subsection 2 explicitly states

array<T, N> a = { initializer-list };

where initializer-list is a comma-separated list of up to N elements whose types are convertible to T

result of code in Xcode 6.1.1 (below)

array<int, 2> key1 = {1, 2}; // warning: suggest braces around initialization of subobject

array<int, 2> key2 = { {1}, {2} }; // error: no viable overload =

array<int, 2> key3 = array<int, 2> { {1}, {2} }; // error: excess elements in struct initializer

array<int, 2> key4 = { {1, 2} }; // no warning and no error

When we look at 14882:2011 8.5 [dcl.init] subsection 1 we see that an 'initializer-list' can optionally contain an 'initializer-clause', which itself can be a 'braced-init-list'. So either way should be correct. Though based on the spec I personally think single braces shouldn't output a compiler warning for a std::array initializer-list, and double braces is overkill.



回答3:

When ignoring the Clang warning with -Wno-missing-braces, I would recommend to enable -Wmissing-field-initializers (or use -Wextra, which also includes it). Otherwise, you miss a useful warning like in this example:

#include <cstdio>

struct A
{
  int i;
  int arr[2];
  int j;
};

void print(const A& a)
{
  printf("i=%d, arr={%d,%d}, j=%d\n", a.i, a.arr[0], a.arr[1], a.j);
}

int main() {
  A a = {1, 2, 3}; // this is the critical line
  print(a); // output: i=1, arr={2,3}, j=0

  A b = {1, {2}, 3};
  print(b); // output: i=1, arr={2,0}, j=3

  A c = {1, {2,0}, 3};
  print(c); // output: i=1, arr={2,0}, j=3

  return 0;
}
$ clang++ -Wall example.cpp
example.cpp:16:13: warning: suggest braces around initialization of
      subobject [-Wmissing-braces]
  A a = {1, 2, 3};
            ^~~~
            {   }
1 warning generated.

$ clang++ -Wall -Wno-missing-braces example.cpp
(no warnings)

$ clang++ -Wall -Wno-missing-braces -Wmissing-field-initializers example.cpp
example.cpp:16:17: warning: missing field 'j' initializer
      [-Wmissing-field-initializers]
  A a = {1, 2, 3};
                ^
1 warning generated.

$ clang++ --version
clang version 3.8.1 (tags/RELEASE_381/final)

For comparison, this is what GCC does:

$ g++ -Wall -Wextra example.cpp
(no warning)

$ g++ -Wall -Wmissing-field-initializers example.cpp
example.cpp: In function ‘int main()’
example.cpp:16:17: warning: missing initializer for member ‘A::j’ [-Wmissing-field-initializers]
   A a = {1, 2, 3};
                 ^

In summary:

  • For Clang, I would recommend -Wno-missing-braces -Wmissing-field-initializers to silence the warning without loosing other useful warnings
  • GCC does not complain in the original std::array<int, 1> x = { 0 }; example, so there is no need to disable any warnings. However, I would recommend to enable -Wmissing-field-initializers (or use -Wextra), as it is not enabled by -Wall.


回答4:

Clang 6.0 suppresses the warning about missing braces. The svn log says:

Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate. In C++, such initialization of std::array types is guaranteed to work by the standard, is completely idiomatic, and the "suggested" alternative from Clang was technically invalid.

So I would omit the braces and disable -Wmissing-braces for Clang prior to 6.0 if it needs to be supported.