C > function > return early | nest | terminate関数のコール | 優先度付き分岐でのif | 関数ポインタ配列テーブル使用


動作環境
組込みC

#include <stdio.h>
#include <stdbool.h>

void process_return_early(bool *flag1, bool *flag2, bool *flag3)
{
    if (*flag1) {
        *flag1 = false;
        printf("flag1\n");
        // 手仕舞い処理
        return;
    }

    if (*flag2) {
        *flag2 = false;
        printf("flag2\n");
        // 手仕舞い処理
        return;
    }

    if (*flag3) {
        *flag3 = false;
        printf("flag3\n");
        // 手仕舞い処理
        return;
    }
}

void process_nest(bool *flag1, bool *flag2, bool *flag3)
{
    if (*flag1) {
        *flag1 = false;
        printf("flag1\n");
    } else {
        if (*flag2) {
            *flag2 = false;
            printf("flag2\n");
        } else {
            if (*flag3) {
                *flag3 = false;
                printf("flag3\n");
            }
        }
    }
    // 手仕舞い処理
 }

int main(void) {
    bool flags[] = { false, true, true };

    process_return_early(&flags[0], &flags[1], &flags[2]);
    process_nest(&flags[0], &flags[1], &flags[2]);

    return 0;
}
run
flag2
flag3

備考

  • 手仕舞い処理をどのように実装するかで、どちらの方法が読みやすいコードになるか
    • return earlyはflagsが増えると縦に伸びる
    • nestはflagsが増えると横に伸びる
    • 一覧性が高いのはどちらか?
    • 1つのフラグに対する処理が見やすいのはreturn earlyかもしれない
    • ifの優先順位を変更しやすいのはreturn early
      • nestの場合、インデントの変更が必要
  • 条件の数によっても読みやすさは異なる
  • decision tableなどの使用も要検討
    • 違うだろうか

code > terminate関数のコール

#include <stdio.h>
#include <stdbool.h>

void terminate_clearing_flag(bool *flag)
{
    *flag = false;
    // 手仕舞い処理
}

void process_call_terminate_func(bool *flag1, bool *flag2, bool *flag3)
{
    if (*flag1) {
        printf("flag1\n");
        terminate_clearing_flag(flag1);
        return;
    }
    if (*flag2) {
        printf("flag2\n");
        terminate_clearing_flag(flag2);
        return;
    }
    if (*flag3) {
        printf("flag3\n");
        terminate_clearing_flag(flag3);
        return;
    }
}

int main(void) {
    bool flags[] = { false, true, true };

    process_call_terminate_func(&flags[0], &flags[1], &flags[2]);
    process_call_terminate_func(&flags[0], &flags[1], &flags[2]);

    return 0;
}

flag1などの命名はポインタ変数と分かる名前の方がいいかもしれない。
(例: pflag1, flag1ptr, flag1Ptr)

謝辞

@tenmyo さんに優先度付き分岐時の良い実装例を教えていただきました。

情報感謝です。

@mt08さんに関数ポインタの配列テーブル使用例を教えていただきました。

情報感謝です。