老プログラマの邪道プログラミング
C言語で enum定数を多用してるプログラムをデバッグしていると、「この整数の元々の enum定数名は、
なんだったのか?」が知りたくなりました。
ぐぐってみると、C++で解説してるサイトはあるのですが、Cでは、
#define STR(var) #var (enum定数 から "enum定数名" を得る)
というマクロぐらいしか見当たりませんでした。なのでCで変換関数を作ってみました。
1.行短縮のため、fopenエラーやmallocエラーなどの基本的エラー処理は省略しています。
2.enum定数が負、重複、不連続の場合も、改良することで対応可能です。
3.オブジェクト指向っぽくコーディングすれば、グローバル変数をstatic constのローカル変数
として保護、隠蔽できるはず。(たぶん)
4.enum宣言が複数ある場合は、その数だけ関数群を作らないといけません。
すなわち汎用性がありません。
汎用性がありません。
(重要なことなので2度書きました。)
最後に、このプログラムを参照するくらいなら、「C++を使う方が何倍もマシ」と思ったあなた!同感です!
C言語 enum定数、enum定数名、整数の変換関数
-
- 記事: 15
- 登録日時: 4年前
C言語 enum定数、enum定数名、整数の変換関数
最後に編集したユーザー tanu_kichi on 2019年11月18日(月) 02:59 [ 編集 7 回目 ]
-
- 記事: 15
- 登録日時: 4年前
Re: C言語 enum定数、enum定数名、整数の変換関数
老プログラマの邪道プログラミング( codeタグが反映されてないため、再送信)
C言語で enum定数を多用してるプログラムをデバッグしていると、「この整数の元々の enum定数名は、
なんだったのか?」が知りたくなりました。
ぐぐってみると、C++で解説してるサイトはあるのですが、Cでは、
#define STR(var) #var ( enum定数 から "enum定数名" を得る)
というマクロぐらいしか見当たりませんでした。なのでCで変換関数を作ってみました。
実行結果
1.行短縮のため、fopenエラーやmallocエラーなどの基本的エラー処理は省略しています。
2.enum定数が負、重複、不連続の場合も、改良することで対応可能です。
3.オブジェクト指向っぽくコーディングすれば、グローバル変数をstatic constのローカル変数
として保護、隠蔽できるはず。(たぶん)
4.enum宣言が複数ある場合は、その数だけ関数群を作らないといけません。
すなわち汎用性がありません。
汎用性がありません。
(重要なことなので2度書きました。)
最後に、このプログラムを参照するくらいなら、「C++を使う方が何倍もマシ」と思ったあなた!同感です!
C言語で enum定数を多用してるプログラムをデバッグしていると、「この整数の元々の enum定数名は、
なんだったのか?」が知りたくなりました。
ぐぐってみると、C++で解説してるサイトはあるのですが、Cでは、
#define STR(var) #var ( enum定数 から "enum定数名" を得る)
というマクロぐらいしか見当たりませんでした。なのでCで変換関数を作ってみました。
// 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
}
//-------------------------------------------------------------------
2.enum定数が負、重複、不連続の場合も、改良することで対応可能です。
3.オブジェクト指向っぽくコーディングすれば、グローバル変数をstatic constのローカル変数
として保護、隠蔽できるはず。(たぶん)
4.enum宣言が複数ある場合は、その数だけ関数群を作らないといけません。
すなわち汎用性がありません。
汎用性がありません。
(重要なことなので2度書きました。)
最後に、このプログラムを参照するくらいなら、「C++を使う方が何倍もマシ」と思ったあなた!同感です!
最後に編集したユーザー tanu_kichi on 2019年11月20日(水) 05:25 [ 編集 11 回目 ]