C++实现的命令行参数管理
在编写可运行程序时,经常需要输入除了可运行文件之外的其它的命令行参数,可以用传统的getopt函数来分析,本文基于面向对象,分析一种管理命令行参数方法 -- 来源于webrtc项目,在阅读过程中,大家分享一下。
一,传统命令行分析
[cpp]
包含头文件:#include<unistd.h>
int getopt(int argc,char * const argv[ ],const char * optstring);
extern char *optarg;
extern int optind, opterr, optopt;
二,命令行参数管理
假设命令行的输入格式的规则如下:
--flag 布尔类型。
--noflag 布尔类型。
--flag=value 等号周边没有空格。
2.1 参数的值封装---FlagValue
这个类对参数的值进行封装,如--prefix=/usr,作为一个命令行参数时,prefix为键,/usr为值。在参数中,在此定义值的类型为布尔、整型、浮点、字符串中的一种。
由于一个值在只能取四种的一种,所以此处用联合类型表示FlagValue。
[cpp]
union FlagValue {
static FlagValue New_BOOL(int b) {
FlagValue v;
v.b = (b != 0);
return v;
}
static FlagValue New_INT(int i) {
FlagValue v;
v.i = i;
return v;
}
static FlagValue New_FLOAT(float f) {
FlagValue v;
v.f = f;
return v;
}
static FlagValue New_STRING(const char* s) {
FlagValue v;
v.s = s;
return v;
}
bool b;
int i;
double f;
const char* s;
};
这个联合类型对命令行中键值对中的值进行封装,可以表示四种类型。
2.2 命令行中键值的表示 -- Flag
这个类是表示一对键值的抽象,包含下列元素:
键值对。包括name和variable_表示键和值。如--prefix=/usr中,name的值为prefix,variable_为/usr的一个表示。
链表维护域。Flag *next_用于指向下一个命令行参数。
comment_表示该参数的解释。
file表示和键值相关的外部文件。
default_表示默认情况下,就是用户没有输入该参数的情况下默认的值。
定义友元类FlagList,因为FlagList需要访问Flag的next_域。
[cpp]
class Flag {
public:
enum Type { BOOL, INT, FLOAT, STRING };
// Internal use only.
Flag(const char* file, const char* name, const char* comment,
Type type, void* variable, FlagValue default_);
// General flag information
const char* file() const { return file_; }
const char* name() const { return name_; }
const char* comment() const { return comment_; }
// Flag type
Type type() const { return type_; }
// Flag variables
bool* bool_variable() const {
assert(type_ == BOOL);
return &variable_->b;
} www.zzzyk.com
int* int_variable() const {
assert(type_ == INT);
return &variable_->i;
}
double* float_variable() const {
assert(type_ == FLOAT);
return &variable_->f;
}
const char** string_variable() const {
assert(type_ == STRING);
return &variable_->s;
}
// Default values
bool bool_default() const {
assert(type_ == BOOL);
return default_.b;
}
int int_default() const {
assert(type_ == INT);
return default_.i;
}
double float_default() const {
assert(type_ == FLOAT);
return default_.f;
}
const char* string_default() const {
assert(type_ == STRING);
return default_.s;
}
// Resets a flag to its default value
void SetToDefault();
// Iteration support
Flag* next() const { return next_; }
// Prints flag information. The current flag value is only printed
// if print_current_value is set.
void Print(bool print_current_value);
private:
const char* file_;
const char* name_;
const char* comment_;
Type type_;
FlagValue* variable_;
FlagValue default_;
Flag* next_;
friend class FlagList; // accesses next_
};
2.3 命令行键值链表--- FlagList
这个类维护一个全局的链表,链表中每一项都是命令行参数解析的结果,如:--prefix=/usr --localstatedir=/var/data 这就表示两个Flag对象,通过Flag对象的next域来关联。
这个类的属性和方法都是静态的,属性只有Flag* list_,用于维护命令行所有输入的参数所组成的链表。
主要方法如下:
SetFkagsFromCommandLine:解析根据命令行的输入,这里传入的是所有的命令行输入。
SplitArgument:解析命令行中具体的一个可以被解析的键值对。
[cpp]
class FlagList {
public:
FlagList();
static Flag* list() { return list_; }
static void Print(const char* file, bool print_current_value);
static Flag* Lookup(const char* name);
static void SplitArgument(const char* arg,
char* buffer, int buffer_size,
const char** name, const char** value,
bool* is_bool);
static int SetFlagsFromCommandLine(int* argc,
const char** argv);
static inline int SetFlagsFromCommandLine(int* argc,
&nbs
补充:软件开发 , C++ ,