在struct中使用typedef来命名和索引文本命令

我正在使用一个简单的命令行应用程序,它接收ASCI文本并将其解释为命令。

我试图通过http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html上的示例来最小化此应用程序中的冗余。

例如:考虑一个解释命名命令的C程序。 可能需要一个命令表,可能是一个声明如下的结构数组:

struct command { char *name; void (*function) (void); }; struct command commands[] = { { "quit", quit_command }, { "help", help_command }, ... }; 

如果必须给每个命令名两次,一次在字符串常量中,一次在函数名中,则更清楚。 将命令名称作为参数的宏可以使其不必要。 字符串常量可以使用字符串化创建,函数名称可以通过将参数与`_command’连接来创建。 以下是它的完成方式:

  #define COMMAND(NAME) { #NAME, NAME ## _command } struct command commands[] = { COMMAND (quit), COMMAND (help), ... }; 

现在,假设我想要一个命令字符串和索引(即:int)值,而不是字符串和函数指针。

  struct command { char *name; int command_idx; }; 

现在,我有一种命名命令的方法,并且有一些我稍后可以用来以编程方式识别每个命令的索引。 例如,我有一个对命令索引进行操作的switch语句。 如果我想处理这些索引,我必须先手动设置值。

我可以手动创建枚举数据类型,但后来我在单独的枚举语句中定义了枚举常量。 IE:枚举命令{cmd_quit = 0,cmd_help},最后,我最终还是要输入两次命令名:一次是通过COMMAND()宏,再一次是我的枚举。

是否有任何方法使用C预处理器允许我创建一个宏创建“命令”结构(使用字符串和int成员),并自动编号int值(command_idx),因为我通过COMMAND()添加更多命令宏?

我也知道我可以对每个可能的命令使用strcmp()调用,并与用户提供的输入进行比较,但是我希望通过command_idx值直接索引命令,而不是strcmp每次都要反对大量命令(即:O(1)而不是O(n))。 我还想避免不惜一切代价多次输入命令名。

谢谢!

您可以使用宏重定义来实现此目的。 首先,创建一个文件,只列出名为commands.inc

 COMMAND(quit) COMMAND(help) ... 

然后,在您的C源代码中,您可以#include "commands.inc"多次,使用不同的COMMAND()定义来控制它的工作方式。 例如:

 struct command { char *name; int command_idx; }; #define COMMAND(NAME) CMD_ ## NAME, enum command_enum { #include "commands.inc" }; #undef COMMAND #define COMMAND(NAME) { #NAME, CMD_ ## NAME }, struct command commands[] = { #include "commands.inc" }; #undef COMMAND 

(请注意,此特定示例依赖于允许尾随的C99改进,在enum声明和复合初始化器的列表末尾 – 您可以通过在末尾添加虚拟条目来轻松解决C89中的问题)。

题:

是否有任何方法使用C预处理器允许我创建一个宏创建“命令”结构(使用字符串和int成员),并自动编号int值(command_idx),因为我通过COMMAND()添加更多命令宏?

是的,因为您已将问题标记为C ++:

 #include  #include  #include  using namespace std; map< string, int > commands; bool register_cmd( int id, string const& name ) { commands[name] = id; return true; } #define COMMAND( name ) \ int const name ## _cmd = __LINE__; \ bool const name ## _reg = register_cmd( name ## _cmd, #name ) COMMAND( exit ); COMMAND( help ); COMMAND( do_stuff ); int cmd_id( string const& name ) { auto const it = commands.find( name ); return (it == commands.end()? -1 : it->second ); } int main() { for( auto it = commands.begin(); it != commands.end(); ++it ) { cout << it->first << " => " << it->second << endl; } cout << "Gimme a command, please: "; string cmd; getline( cin, cmd ); switch( cmd_id( cmd ) ) { case exit_cmd: cout << "You typed an EXIT command, which has id " << exit_cmd << endl; break; default: cout << "Hey, why not try an 'exit' command?" << endl; } } 

我只使用map而不是花哨的新C ++ 11哈希表,因为map适用于较旧的编译器,并且在这里没有真正需要剃纳秒。

干杯&hth。,