C言語 enum定数、enum定数名、整数の変換関数

tanu_kichi
記事: 15
登録日時: 4年前

C言語 enum定数、enum定数名、整数の変換関数

投稿記事 by tanu_kichi » 4年前

老プログラマの邪道プログラミング

C言語で enum定数を多用してるプログラムをデバッグしていると、「この整数の元々の enum定数名は、
なんだったのか?」が知りたくなりました。

ぐぐってみると、C++で解説してるサイトはあるのですが、Cでは、
#define STR(var) #var (enum定数 から "enum定数名" を得る)
というマクロぐらいしか見当たりませんでした。なのでCで変換関数を作ってみました。

1.行短縮のため、fopenエラーやmallocエラーなどの基本的エラー処理は省略しています。
2.enum定数が負、重複、不連続の場合も、改良することで対応可能です。
3.オブジェクト指向っぽくコーディングすれば、グローバル変数をstatic constのローカル変数
  として保護、隠蔽できるはず。(たぶん)
4.enum宣言が複数ある場合は、その数だけ関数群を作らないといけません。
  すなわち汎用性がありません。
  汎用性がありません。
 (重要なことなので2度書きました。)

最後に、このプログラムを参照するくらいなら、「C++を使う方が何倍もマシ」と思ったあなた!同感です!
最後に編集したユーザー tanu_kichi on 2019年11月18日(月) 02:59 [ 編集 7 回目 ]

tanu_kichi
記事: 15
登録日時: 4年前

Re: C言語 enum定数、enum定数名、整数の変換関数

投稿記事 by tanu_kichi » 4年前

老プログラマの邪道プログラミング( codeタグが反映されてないため、再送信)

C言語で enum定数を多用してるプログラムをデバッグしていると、「この整数の元々の enum定数名は、
なんだったのか?」が知りたくなりました。

ぐぐってみると、C++で解説してるサイトはあるのですが、Cでは、
#define STR(var) #var ( enum定数 から "enum定数名" を得る)
というマクロぐらいしか見当たりませんでした。なのでCで変換関数を作ってみました。

CODE:

// enum_to_name.c
// for function of enum_to_name(), num_to_name(), name_to_num()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define TRUE  1
#define FALSE 0
#define BUF_SIZE                256
#define ENUMERATOR_SIZE 32
enum color_name {
  UNDEFINE_COLOR,
  RED,
  BLUE,
  GREEN,
  UNKNOWN_COLOR,
};
typedef struct enum_data_ {
  char name[ENUMERATOR_SIZE];
  int num;
} Enum_data_;
Enum_data_ *enmrtr;
int max_enmrtr;
void initialize_enmrtr_data(void);
void finalize_enmrtr_data(void);
int get_max_enmrtr(void);
int have_str(char *str, char *buf);
void set_enmrtr_data(void);
void set_enmrtr_record(int count, int num, char *buf);
char *enum_to_name(enum color_name enumerator); // enumerator to name_string
char *num_to_name(int num);                                   // int_number to name_string
int name_to_num(char *name);                                 // name_string to int_number
//-------------------------------------------------------------------
int main(void)
{
  initialize_enmrtr_data();
  fprintf(stdout, "%-14s:%d\n", num_to_name(0), UNDEFINE_COLOR);
  fprintf(stdout, "%-14s:%d\n", num_to_name(1), RED);
  fprintf(stdout, "%-14s:%d\n", enum_to_name(BLUE), BLUE);
  fprintf(stdout, "%-14s:%d\n", num_to_name(3), name_to_num("GREEN"));
  fprintf(stdout, "%-14s:%d\n", enum_to_name(4), UNKNOWN_COLOR);
  finalize_enmrtr_data();
  return 0;
}
//-------------------------------------------------------------------
void initialize_enmrtr_data(void)
{
  max_enmrtr = get_max_enmrtr();
  enmrtr = (Enum_data_ *) malloc(sizeof(Enum_data_) * (max_enmrtr));
  for (int i = 0; i < max_enmrtr; ++i) {
    memset(enmrtr[i].name, '\0', ENUMERATOR_SIZE);
  }
  set_enmrtr_data();
}
//-------------------------------------------------------------------
void finalize_enmrtr_data(void)
{
  free(enmrtr);
}
//-------------------------------------------------------------------
int get_max_enmrtr(void)
{
  FILE *fp = fopen(__FILE__, "r");     // open myself_source_code
  int count = -1;
  char buf[BUF_SIZE];
  memset(buf, '\0', BUF_SIZE);
  while (fgets(buf, BUF_SIZE, fp) != NULL) {
    if (have_str("UNDEFINE_COLOR", buf) == TRUE) {
      do {
        ++count;
        if (fgets(buf, BUF_SIZE, fp) == NULL) {
          fprintf(stderr, "Error : file over read\n");
          exit(1);
        }
        if (have_str("UNKNOWN_COLOR", buf) == TRUE) {
          ++count;
          fclose(fp);
          return count + 1;          // begin_of_count = 0 , so max_enmrtr = count + 1
        }
      } while (1);
      fprintf(stderr, "Error : unexpected do_while_end\n");
      exit(1);
    }
  }
  fprintf(stderr, "Error : unexpected while_end\n");
  exit(1);
}
//-------------------------------------------------------------------
int have_str(char *str, char *buf)
{
  int str_len = strlen(str);
  int buf_len = strlen(buf);
  for (int i = 0; i < buf_len; ++i) {
    if (strncmp(&buf[i], str, str_len) == 0) return TRUE;  // WARNING when STR, STR2, STR21
  }
  return FALSE;
}
//-------------------------------------------------------------------
void set_enmrtr_data(void)
{
  FILE *fp = fopen(__FILE__, "r");   // open myself_source_code
  int count = -1;
  char buf[BUF_SIZE];
  memset(buf, '\0', BUF_SIZE);
  while (fgets(buf, BUF_SIZE, fp) != NULL) {
    if (have_str("UNDEFINE_COLOR", buf) == TRUE) {
      do {
        ++count;
        set_enmrtr_record(count, count, buf);
        if (fgets(buf, BUF_SIZE, fp) == NULL) {
          fprintf(stderr, "Error : file over read\n");
          exit(1);
        }
      } while (count < max_enmrtr);
      fclose(fp);
      return;
    }
  }
  fprintf(stderr, "Error : unexpected while_end\n");
  exit(1);
}
//-------------------------------------------------------------------
void set_enmrtr_record(int count, int num, char *buf)
{
  int buf_len = strlen(buf);
  for (int i = 0; i < buf_len; ++i) {
    if (isalnum(buf[i]) == 0 && buf[i] != '_') continue; // WARNING when first_char is digit
    int j = 0;
    while (isalnum(buf[i]) != 0 || buf[i] == '_') {
      enmrtr[count].name[j++] = buf[i++];
    }
    break;
  }
  enmrtr[count].num = num;
}
//-------------------------------------------------------------------
char *enum_to_name(enum color_name enumerator)
{
  return enmrtr[enumerator].name;
}
//-------------------------------------------------------------------
char *num_to_name(int num)
{
  for (int i = 0; i < max_enmrtr; ++i)
    if (enmrtr[i].num == num) return enmrtr[i].name;
  fprintf(stderr, "Warning : not found number in enum\n");
  return "";
}
//-------------------------------------------------------------------
int name_to_num(char *name)
{
  int name_len = strlen(name);
  for (int i = 0; i < max_enmrtr; ++i) {
    if (strlen(enmrtr[i].name) != name_len) continue;
    if (strncmp(enmrtr[i].name, name, name_len) == 0) return enmrtr[i].num;
  }
  fprintf(stderr, "Warning : not found enumerator_name in enum\n");
  return -1;        // WARNING when enumerator = -1 in enum declaration
}
//-------------------------------------------------------------------
実行結果

CODE:

UNDEFINE_COLOR:0
RED                        :1
BLUE                      :2
GREEN                   :3
UNKNOWN_COLOR :4
1.行短縮のため、fopenエラーやmallocエラーなどの基本的エラー処理は省略しています。
2.enum定数が負、重複、不連続の場合も、改良することで対応可能です。
3.オブジェクト指向っぽくコーディングすれば、グローバル変数をstatic constのローカル変数
  として保護、隠蔽できるはず。(たぶん)
4.enum宣言が複数ある場合は、その数だけ関数群を作らないといけません。
  すなわち汎用性がありません。
  汎用性がありません。
 (重要なことなので2度書きました。)

最後に、このプログラムを参照するくらいなら、「C++を使う方が何倍もマシ」と思ったあなた!同感です!
最後に編集したユーザー tanu_kichi on 2019年11月20日(水) 05:25 [ 編集 11 回目 ]