いくつかのCコードをクリーンアップし、Debianパッケージをビルドしようとしています。 makefileは-Wallを使用するように設定されていますが、デビルドは-Wpedanticを使用します。
コードはデータポインタを関数ポインタに変換するため、これは「良いこと」です(ISO Cでは許可されず、非常に危険です...一部のアーキテクチャでは、データとコードが異なるアドレス空間にある可能性があります)。
ただし、コードはスイッチステートメントでも範囲を使用します。これはgcc(およびclang)拡張であるため、-Wpedanticに問題があります。
case QNAP_PICSTS_SYS_TEMP_0 ... QNAP_PICSTS_SYS_TEMP_70:
(#defineは列挙型ではありません)
スイッチスコープの使用はカーネルで一般的であり、いくつかのif / elseロジックでデフォルト値を使用するように再コーディングできますが、実際には遅いです(ジャンプテーブルとコード)。
それでは、1番はこの機能のみを許可するオプションがあり、2番(ボーナスポイント用)はDebianパッケージルールでどのように設定されますか?
オプションは次のとおりです。
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Warning-Options.html
ベストアンサー1
私は広い範囲を使ってswitch / case / defaultのコンパイラ出力を見ました。 if/elseで実装されたのと同じコードと比較しました。ソースコード)。
名前とは別に、これはまったく同じバイナリコード(Godboltのコンパイラブラウザ)、debian 12 のデフォルトの GCC 12.2 で使用されている場合、およびdpkg-buildflags
debian で使用される関連コンテンツとともに使用される場合。
幸いなことに、最新のコンパイラは簡単なものを見て、if(state == constant) expr; else if(state == other_constant)…
長さが短ければジャンプテーブルに変換できます。したがって、コードはスイッチ/ケースとまったく同じです。これはすでに発生している-O1
ため、危険な最適化ではありません。
そしてさらに驚くべきことに、getのような構造はcase 5 ... 74:
75との比較に変換されます(ジャンプテーブルがすでに5未満のケースを処理した後)。
したがって、実際には、よりもきれいに見えると思わない限り、現代のコードでswitch
使用する理由はありません。私は知らない - そして私はあなたのコンパイラもこれをしないと思う:より厳しい範囲指定はブロックを使用して達成される。case
case CONSTANT: … break;
if(state == CONSTANT){ … }
1つの例外がありますが、これはもちろんのこと、基本的になしでcase:
シミュレーションbreak
できることです。goto
goto
switch(state) {
case 1:
value += 0.2f;
case 2:
retval = 1.0f/value;
break
// …
}
仮説と同じ
if (state == 1) {
value += 0.2f;
goto label_in_two;
}
else if(state == 2)
label_in_two:
retval = 1.0f/value;
}
(私たち全員が意志を忘れたことによって起こる間違いを知っています。そうでない場合は、break;
意志を使用すると同じ問題が発生します。goto
非常に注意深い。 )
これは実際に有限状態機械を構築する人のための便利な構成であり、範囲と共に使用するためのものではないことを理解してください。switch
古いコンパイラに比べてまったく利点がなく、if/else if
明確な制御がない場合、ストリームには多数のエラーソースがあります。
だから私は振り返ってみると、現代のコンパイラの最適化の知識に基づいて、GNUのcase
スコープ機能が間違って考慮されたと思います。したがって、警告は合理的でした。
だから私はこの警告を削除する正しい方法はswitch
//を//構文に変換することであるという結論に達しました。case
default
if
else if
else