AVR プロジェクトの PROGMEM で文字列の配列をきれいに定義する方法を探しています。コマンド文字列のリストを必要とするコマンド ライン プロセッサがあります。
AVR アーキテクチャでこれを行う従来の方法は、各文字列を個別に定義してから、それらの文字列へのポインターの配列を定義することです。これは非常に冗長で醜いです:
typedef struct
{
PGM_P str; // pointer to command string
uint8_t str_len; // length of command string
uint8_t id; // CLI_COM_* ID number
} CLI_COMMAND_t;
const char CLI_STR_TEMP[] PROGMEM = "TEMP";
const char CLI_STR_POWER[] PROGMEM = "POWER";
...
const CLI_COMMAND_t cli_cmd_table[] = { { CLI_STR_TEMP, sizeof(CLI_STR_TEMP), CLI_COM_TEMP },
{ CLI_STR_POWER, sizeof(CLI_STR_POWER), CLI_COM_POWER },
...
};
(CLI_COM_* は列挙されたインデックスですが、関数ポインターなどで置き換えることができます)
この混乱は、次のようなマクロを使用して文字列を定義し、テーブルを構築することで減らすことができます。
#define FLASH_STRING(NAME...) const char CLI_STR_ ## NAME [] PORGMEM = #NAME;
#define FSTR(NAME...) { CLI_STR_ ## NAME, sizeof(CLI_STR_ ## NAME), CLI_COM_ ## NAME) }
FLASH_STRING(TEMP);
FLASH_STRING(POWER);
CLI_COMMAND_t cli_cmd_table[] = { FSTR(TEMP), FSTR(POWER) };
(テストされていませんが、うまくいくはずです)
ただし、すべての文字列を一度だけ定義し、マクロで個々の文字列とポインター/サイズ/列挙参照の配列の両方を生成したいと考えています。
Arduino プラットフォームには FLASH_STRING_ARRAY マクロがありますが、これはよくわかりませんが、どちらもコンパイルされていないようです。ここで見ることができます: http://pastebin.com/pMiV5CMrおそらく、C++ のみか何かです。また、グローバルではなく、関数内でのみ使用できるようです。
AVR の文字列テーブルは長い間面倒でエレガントではありませんでした。必要なコードを生成するための小さなプログラムを作成する以外に、マクロを使用してコードを定義する方法があると便利です。
ボーナス ポイント: CLI_COM_* 定数を同じマクロ (列挙型または #defines のいずれか) で生成します。
編集:これの別の名前は、マクロによる反復宣言であると思います。
解決策: luser のおかげで、次の解決策を思いつきました。
typedef struct
{
PGM_P str; // pointer to command string
uint8_t str_len; // length of command string
uint8_t id; // CLI_COM_* ID number
} CLI_COMMAND_LUT_t;
#define COMMAND_TABLE \
ENTRY(testA) \
ENTRY(testB) \
ENTRY(testC)
enum {
#define ENTRY(a) CLI_COM_ ## a,
COMMAND_TABLE
#undef ENTRY
};
#define ENTRY(a) const char CLI_STR_ ## a PROGMEM = #a;
COMMAND_TABLE
#undef ENTRY
CLI_COMMAND_LUT_t command_lut[] PROGMEM = {
#define ENTRY(a) {CLI_STR_ ## a, sizeof(CLI_STR_ ## a), CLI_COM_ ## a},
COMMAND_TABLE
#undef ENTRY
};
は、プリプロセッサから次の出力を生成します。
typedef struct
{
PGM_P str;
uint8_t str_len;
uint8_t id;
} CLI_COMMAND_LUT_t;
enum {
CLI_COM_testA, CLI_COM_testB, CLI_COM_testC,
};
const char CLI_STR_testA PROGMEM = "testA"; const char CLI_STR_testB PROGMEM = "testB"; const char CLI_STR_testC PROGMEM = "testC";
CLI_COMMAND_LUT_t command_lut[] PROGMEM = {
{CLI_STR_testA, sizeof(CLI_STR_testA), CLI_COM_testA}, {CLI_STR_testB, sizeof(CLI_STR_testB), CLI_COM_testB}, {CLI_STR_testC, sizeof(CLI_STR_testC), CLI_COM_testC},
};
したがって、これらすべてを 1 つの領域にまとめることができ、文字列名とコードの参照の両方として機能する、各コマンドのシンプルで最も重要な 1 つの定義になります。
どうもありがとうございました。