web-dev-qa-db-ja.com

gcc / clangの「-Wmissing-braces」警告を無視するのは賢明ですか?

次のプログラムを検討してください。

#include <array>

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

最初の初期化により、gcc 4.7.2で警告が表示されます...

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

...およびclang 3.1

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

標準に関する限り、少なくともこの例では、二重中括弧と単一中括弧の間に違いはないはずです。

警告に対処するには、2つの方法があります。

  1. オフにするだけ
  2. コードを修正して、コンパイラが満足するようにします

何を提案しますか?私見、二重巻きの表現はややsomewhatいように見えます。一方、より複雑な例では、警告によって実際の問題が検出される場合があります。警告があなたを助けたであろう例を知っていますか?

47
Philipp Claßen

-Wmissing-bracesはGCCの-Wall(C++モードの場合)、4.8の時点で、あなたが説明する正確な理由によります。 GCCの現在のバージョンでは、警告を無効にするか無視します。

この警告は、おそらく次のようなコードを対象としています。

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

しかし、私見、それはすでに-Wmissing-field-initializers、元のコードについて警告しません。

46
user743382

Xcode 6.1.1(2015年3月9日現在のバージョン)でも同じ警告が表示されます。各サブオブジェクトの周りに余分な括弧を追加すると、エラーが発生します。初期化リスト全体に余分なブレースを追加すると、警告は消えます。標準仕様14882:2011 23.3.2.1 [array.overview]サブセクション2によると、

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

ここで、initializer-listは、型がTに変換可能な最大N個の要素のコンマ区切りリストです。

xcode 6.1.1のコードの結果(下)

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

14882:2011 8.5 [dcl.init]サブセクション1を見ると、 'initializer-list'にオプションで 'initializer-clause'を含めることができます。したがって、どちらの方法も正しいはずです。仕様にもとづきますが、個人的には、単一の波括弧はstd :: array initializer-listのコンパイラ警告を出力すべきではなく、二重の波括弧は過剰です。

Clang 6.0は、括弧の欠落に関する警告を抑制します。 svnログは言う:

それ自体が集約である単一のフィールドで構造体を集約初期化するとき、-Wmissing-braces警告を抑制します。 C++では、このようなstd :: array型の初期化は標準によって機能することが保証されており、完全に慣用的であり、Clangからの「推奨」代替案は技術的に無効でした。

したがって、サポートが必要な場合は、中括弧を省略し、6.0より前のClangの-Wmissing-bracesを無効にします。

4
proski

-Wno-missing-bracesでClangの警告を無視するときは、-Wmissing-field-initializersを有効にすることをお勧めします(または、-Wextraも使用します)。そうしないと、次の例のような便利な警告を見逃します。

#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)

比較のために、これがGCCの機能です。

$ 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};
                 ^

要約すれば:

  • Clangでは、-Wno-missing-braces -Wmissing-field-initializersをお勧めします。他の有用な警告を失うことなく警告を黙らせる
  • GCCは元のstd::array<int, 1> x = { 0 };の例では文句を言わないので、警告を無効にする必要はありません。ただし、-Wmissing-field-initializersでは有効にならないため、-Wextraを有効にする(または-Wallを使用する)ことをお勧めします。
3
Philipp Claßen