web-dev-qa-db-ja.com

Ifステートメントの多くの条件をエレガントな方法で処理する方法

以下を(より大きな抽象化なしで)書くためのより構文的に美しい/単により良い方法はありますか?

 if (usart_error.CRCError == true || usart_error.DMATransferError == true ||
     usart_error.FramingError == true || usart_error.NoiseError == true ||
     usart_error.OverrunError == true || usart_error.ParityError == true )
 {
    //...
 }

私はOOP組み込みシステムにC++の唯一の側面を使用しています。

注: usart_errorは私のクラスなので、必要に応じて調整できます。

配列でビットマスクを使用して、1などがあるかどうかを確認することをお勧めしましたが、これは私の好みに合わせて抽象化しすぎています。

4
NoOne

抽象化または変更を拒否した場合usart_error次に、空白を使用して私の目を憐れんでください。

if  (  usart_error.CRCError
    || usart_error.DMATransferError
    || usart_error.FramingError
    || usart_error.NoiseError
    || usart_error.OverrunError 
    || usart_error.ParityError
    )
{
    //...
}

これは Haskellスタイル を連想させます。そもそもこの必要性を回避するのが最善ですが、これには各行間の論理演算が一目でわかるという利点があり、usart_errorは全体で使用され、各エラープロパティは縦のリスト形式で表示されます。

確かに、それはコードの行を消費しますが、ふわふわしたコードは圧縮されたコードよりも消化しやすいコードだと思います。アジャイルマニフェストが言うように、密度よりもまばらです。

このフォームは、タブの専制政治の下に住んでいる人と互換性があります。他の調整があります。

わかりやすい名前を付けて抽象化してください(実行してください)(実行してください)場合は、複雑さが他の場所に現れる可能性が高く、ほぼ同じ問題が発生します。それらの場合、私はこのようなものを使います:

return usart_error.CRCError
    || usart_error.DMATransferError
    || usart_error.FramingError
    || usart_error.NoiseError
    || usart_error.OverrunError 
    || usart_error.ParityError
;

設計上の決定によって、この複雑なコードを書くことを強制されていないかどうか、少し考えてみる価値があります。これが故障したり、何らかの方法で回避できる場合は、この問題を処理する簡単な方法を見つけるのに時間をかける価値があります。一見すると、このコードに型階層が隠れていないかと思います。

でもこうするのなら、目に優しくしてください。

10
candied_orange

_usart_error_が独自のクラスである場合、これらの条件を短くするだけでなく、よりわかりやすく記述できるように、わかりやすい名前のメソッドを追加する必要があります。

たとえば、.transient_error().nonrecoverable_error()は、.transfer_error()とは対照的にcontent_error()でうまくいくかもしれません-または単にis_error()

6
Kilian Foth

これがまさに関数の目的です。条件を関数に抽出します。ここでは無料の関数を使用していますが、UsartErrorのメンバー関数に等しく入れることもできます。

bool is_fatal_error(const UsartError & usart_error) {
    return usart_error.CRCError
        || usart_error.DMATransferError 
        || usart_error.FramingError
        || usart_error.NoiseError
        || usart_error.OverrunError
        || usart_error.ParityError
    ;
}

次に、メインコードは次のようになります。

if (is_fatal_error(usart_error))
{
    //...
}

3

ビットマスクが「抽象化」としてどのように修飾されるかについては、私はかなり迷っています(実際、それは一般的には正反対です)。

しかし、とにかくそれを避けたいと思うなら、おそらくboolsを配列またはベクトルに入れて、さまざまなエラーの名前を添え字として配列/ベクトルに入れます。このようにして、特定の値のセットのいずれかがtrueであるかどうかを検出するループを簡単に作成できます。

enum { ERROR_FIRST, 
       CRCError = ERROR_FIRST, 
       DMATransferError, 
       FramingError, 
       NoiseError, 
       OverrunError, 
       ParityError, 
       ERROR_LAST};

bool usart_errors[ERROR_LAST];

bool error_occurred = false;

for (int i=ERROR_FIRST; i<ERROR_LAST; i++)
    error_occurred |= usart_errors[i];

if (error_occurred) ...
0
Jerry Coffin

すべての個々のエラーフラグを個別にテストする必要はありません。

実行しているテストの種類(つまり、エラーが発生したかどうか)については、Cのビットフィールドを使用できます。

#include <stdio.h>
#include <stdlib.h>

static union {
    unsigned int value;
    struct {
        unsigned int CRC:1;
        unsigned int DMATransfer:1;
        /* ... */
        unsigned int Overrun:1;
        unsigned int Parity:1;
    };
} usart_error;

    int
main(void) {
    usart_error.value = 0;
    /* ... */
    if (usart_error.Overrun)
        printf("Overrun\n");
    return usart_error.value ? 1 : 0;
}

この例では、オーバーランエラーが発生した場合は「Overrun」が出力され、何らかのエラーが発生した場合はexit(1)が出力されます。

0
Ray Butterworth