Switchステートメントでの暗黙的なフォールスルーに関するGCC 7からの警告をキャッチしています。以前は、Clangでそれらをクリアしました(以下にコメントの理由があります):
_g++ -DNDEBUG -g2 -O3 -std=c++17 -Wall -Wextra -fPIC -c authenc.cpp
asn.cpp: In member function ‘void EncodedObjectFilter::Put(const byte*, size_t)’:
asn.cpp:359:18: warning: this statement may fall through [-Wimplicit-fallthrough=]
m_state = BODY; // fall through
^
asn.cpp:361:3: note: here
case BODY:
^~~~
_
GCCマニュアル は__attribute__ ((fallthrough))
を使用するように述べていますが、移植性はありません。また、マニュアルには "と記載されています。..警告を黙らせるためにフォールスルーコメントを追加することもできます"が、FALLTHRU
のみを提供しています(これが本当に唯一の選択肢ですか?):
_switch (cond)
{
case 1:
bar (0);
/* FALLTHRU */
default:
…
}
_
ClangとGCCの両方でフォールスルー警告をクリアするポータブルな方法はありますか?もしそうなら、それは何ですか?
GCCは、次のように、マーカーコメントを独自の行に期待しています。
m_state = BODY;
// fall through
case BODY:
また、マーカーはcase
ラベルの直前に来る必要があります。中間の閉じ中括弧}
は存在できません。
fall through
は、GCCによって認識されるマーカーの1つです。 FALLTHRU
だけではありません。完全なリストについては、 -Wimplicit-fallthrough
オプション のドキュメントを参照してください。こちらもご覧ください Red Hat Developerブログに投稿 。
(これもClangと互換性があるはずですが、現在のトランク(r308163)でこれを確認するための切り替えフォールスルー警告を出すことはできません。)
マーカーコメントで警告を無視することは、コンパイラが実際にコメントを認識した場合にのみ機能することに注意してください。プリプロセッサが個別に実行される場合、GCCの -C
オプション )と同様に、コメントを保持するように指示する必要があります。たとえば、 ccache を使用した誤った警告を回避するには、コンパイル時に-C
フラグを指定するか、ccacheの最新バージョンではkeep_comments_cpp
オプションを使用する必要があります。
C++ 17 [[fallthrough]]
例:
int main(int argc, char **argv) {
switch (argc) {
case 0:
argc = 1;
[[fallthrough]];
case 1:
argc = 2;
};
}
コンパイル:
g++ -std=c++17 -Wimplicit-fallthrough main.cpp
[[fallthrough]];
を削除すると、GCCは警告します:
main.cpp: In function ‘int main()’:
main.cpp:5:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
argc = 1;
~~^~~
main.cpp:6:9: note: here
case 1:
^~~~
また、この例から、2つのケースにまたがった場合にのみ警告が発生することに注意してください。最後のcaseステートメント(ここではcase 1
)は、break
がなくても警告を生成しません。
次の構成体も警告を生成しません。
#include <cstdlib>
[[noreturn]] void my_noreturn_func() {
exit(1);
}
int main(int argc, char **argv) {
// Erm, an actual break
switch (argc) {
case 0:
argc = 1;
break;
case 1:
argc = 2;
}
// Return also works.
switch (argc) {
case 0:
argc = 1;
return 0;
case 1:
argc = 2;
}
// noreturn functions are also work.
// https://stackoverflow.com/questions/10538291/what-is-the-point-of-noreturn/47444782#47444782
switch (argc) {
case 0:
argc = 1;
my_noreturn_func();
case 1:
argc = 2;
}
// Empty case synonyms are fine.
switch (argc) {
case 0:
case 1:
argc = 2;
}
// Magic comment mentioned at:
// https://stackoverflow.com/a/45137452/895245
switch (argc) {
case 0:
argc = 1;
// fall through
case 1:
argc = 2;
}
switch (argc) {
// GCC extension for pre C++17.
case 0:
argc = 1;
__attribute__ ((fallthrough));
case 1:
argc = 2;
}
switch (argc) {
// GCC examines all braches.
case 0:
if (argv[0][0] == 'm') {
[[fallthrough]];
} else {
return 0;
}
case 1:
argc = 2;
}
}
最後の例から、GCCはすべての可能なブランチを調べ、それらのいずれかが[[fallthrough]];
またはbreak
またはreturn
を持たない場合に警告することがわかります。
このGEM5にヒントを得たスニペット のようなマクロを使用して、機能の可用性を確認することもできます。
#if defined __has_cpp_attribute
#if __has_cpp_attribute(fallthrough)
#define MY_FALLTHROUGH [[fallthrough]]
#else
#define MY_FALLTHROUGH
#endif
#else
#define MY_FALLTHROUGH
#endif
参照: https://en.cppreference.com/w/cpp/language/attributes/fallthrough
GCC 7.4.0、Ubuntu 18.04でテスト済み。
こちらもご覧ください
この質問のCバージョン: GCC 7、-Wimplicit-fallthrough warnings、およびそれらをクリアするポータブルな方法?
クリーンCソリューション:
int r(int a) {
switch(a) {
case 0:
a += 3;
case 1:
a += 2;
default:
a += a;
}
return a;
}
になる:
int h(int a) {
switch(a) {
case 0:
a += 3;
goto one;
one:
case 1:
a += 2;
goto others;
others:
default:
a += a;
}
return a;
}