2017-12-19 15 views
4

対応するエラーメッセージにマップする必要があるエラーコード(0,1,10,11,20,30,40、...)があります。エラーコードは、配列内のインデントとして便利に使うことができないので(疎で無駄になります)、これはマクロやenumで何らかの形で達成できると考えています。整数をconst文字列にプログラムでマップする方法は?

私は基本的に関数const char *my_strerror(int errorcode)を作成しようとしています。

const char *err00 = "an error message"; 
const char *err01 = "a different one"; 
const char *err10 = "another one"; 

const char* chatter_strerror(int error){ 
    switch(error){ 
     case 0: 
      return err00; 
     case 1: 
      return err01; 
     case 10: 
      return err10; 

     .... // 10 more cases 
    } 
} 

確かにこれを行うにはよりエレガントな方法がありますか?

+0

あなたは可能な限り効率的にスイッチケースを下げるために、あなたのコンパイラを信頼することができます。はい、これがあなたの最善の策です。 –

+0

マクロはコンパイル時に評価されるので、マクロではできません。私はあなたのエラーコードが実行時に生成されると確信しています。 –

+0

@AjayBrahmakshatriyaいずれかのエラーコードは、1つのエラーメッセージにのみ対応し、コンパイル時には静的です。そして、私はアプローチの効率には関心がありません、私は実装の優雅さ、シンプルさ、拡張性、そして冗長性にもっと関心を持っています。 – vasia

答えて

4

解決策の1つは、エラーコードのフィールドがintで、エラーメッセージのフィールドがchar *であるエラーメッセージ構造を作成することです。次に、エラーコードstructの配列をエラーコードとメッセージで初期化することができます。この方法では、新しいエラーメッセージでコードを簡単に更新できます。エラーメッセージの配列の最後のstructが、.msgフィールドにヌルポインタを持つセンチネルとして使用されている場合、配列を反復処理する関数は、それに含まれる要素の数

ここは例です。 get_error()機能は、アレイ上でループし、目的のエラーコードが発生したときにループから抜け出します。センチネル値に達して一致するものが見つからない場合は、「Unrecognized error code」というメッセージが返されます。新しいエラーメッセージがerror_codes[]アレイに追加されると、get_error()関数を変更する必要はありません。

#include <stdio.h> 

struct Errors 
{ 
    const char *msg; 
    int code; 
}; 

struct Errors error_codes[] = { 
    { .code = 1, .msg = "input error" }, 
    { .code = 5, .msg = "format error" }, 
    { .code = 10, .msg = "allocation error" }, 
    { .msg = NULL } 
}; 

const char * get_error(int err_code); 

int main(void) 
{ 
    printf("Error: %s\n", get_error(1)); 
    printf("Error: %s\n", get_error(5)); 
    printf("Error: %s\n", get_error(10)); 
    printf("Error: %s\n", get_error(-1)); 

    return 0; 
} 

const char * get_error(int err_code) 
{ 
    struct Errors *current = error_codes; 
    const char *ret_msg = "Unrecognized error code"; 

    while (current->msg) { 
     if (current->code == err_code) { 
       ret_msg = current->msg; 
       break; 
     } 
     ++current; 
    } 

    return ret_msg; 
} 

OPはintエラーコードを指定するだけでなく、enum Sに言及しています。ここにはenumを使用した変更があります。ここでenumを使用する利点の1つは、読みやすさの向上です。欠点は、エラーメッセージが変更されたときにコードを2か所で変更する必要があることです。

#include <stdio.h> 

/* Modify both the Error_Codes enum and the following error_codes[] array 
    when adding new error messages. */ 

enum Error_Codes { 
    ERRINPUT = 1, 
    ERRFORMAT = 5, 
    ERRALLOC = 10 
}; 

struct Errors 
{ 
    const char *msg; 
    enum Error_Codes code; 
}; 

struct Errors error_codes[] = { 
    { .code = ERRINPUT, .msg = "input error" }, 
    { .code = ERRFORMAT, .msg = "format error" }, 
    { .code = ERRALLOC, .msg = "allocation error" }, 
    { .msg = NULL } 
}; 

const char * get_error(enum Error_Codes err_code); 

int main(void) 
{ 
    printf("Error: %s\n", get_error(ERRINPUT)); 
    printf("Error: %s\n", get_error(ERRFORMAT)); 
    printf("Error: %s\n", get_error(ERRALLOC)); 
    printf("Error: %s\n", get_error(-1)); 

    return 0; 
} 

const char * get_error(enum Error_Codes err_code) 
{ 
    struct Errors *current = error_codes; 
    const char *ret_msg = "Unrecognized error code"; 

    while (current->msg) { 
     if (current->code == err_code) { 
       ret_msg = current->msg; 
       break; 
     } 
     ++current; 
    } 

    return ret_msg; 
} 

プログラムの出力:

Error: input error 
Error: format error 
Error: allocation error 
Error: Unrecognized error code 
+0

これは私が取り上げたアプローチではありませんが、それは十分にエレガントです。もし私が11以上のエラーコードを持っていたら、これは道のりになります。私はconst *の配列とそれにインデックスを付けるために使用する列挙型のために解決しました。私はあなたのアプローチが好きですが、私が完全にそれを販売していない唯一の理由は、構造体の配列を反復してエラーコードを比較しなければならないということです。 – vasia

+0

もちろん、猫の皮膚を作る方法はたくさんあります。この方法について私が気に入っているのは、エラーメッセージの変更や追加が簡単だということです。コードを修正する必要があるのは、1か所だけです。エラーメッセージに関して、私は効率が第一の関心事だとは思わない。一方、メンテナンスの容易さは根本的に重要なようです。 –

+0

あなたは絶対に正しいです、私はあなたのアプローチに切り替えることを検討しています。誰もあなたのものより優れている生成マクロ/列挙型を使用するソリューションを投稿していない場合は、まもなくこれを受け入れたものとしてマークします。 – vasia

関連する問題