main()函数及其参数

main()函数及其参数
C++
标准允许主函数main()有或没有参数列表。 您能在主函数main()中使用一个或更多的参数。 如下是一些惯例:
int main(int argc, char *argv[])
第一个参数argc,指明有多少个参数将被传递给主函数main(),真正的参数以字符串数组(即第2个参数argv[])的形式来传递。每一个字符串均有自己意思。在这句法上面, 记住, argc代表参数的数量, main()函数本身是在索引0为的第一参数。 所以, argc总是至少为1 。它的总数是从argv列阵的元素数目。 这意味着, argv[0]的值是至关重要的。 如果用户在控制台环境中程序名称后键入含参数的指令, 那么随后的参数将传递给argv[1] 例如, 如果程序名称为main,并且已经事先编译好了,这时如果用户键入:
D:/MyPrograms/AConsoleApp/main 68

68将会传递给argv[1]
当然取决于你怎么样来编写程序了,也许你的用户将可以输入如下指令:
D:/MyPrograms/AConsoleApp/main 68 1250.50
因为参数argv是一些字符串,将这些字符串转换为你需要的值就是我们程序员的任务了。所以用户输入下面这样的指令:
D:/MyPrograms/AConsoleApp/main 68 1250.50
并不意味着68是一个整形,而1250.50是一个double,当然C/C++编译器为我们提供了一些转换函数,你可以用atoi()函数把字串68转换为整形。同样,你可以用atof()函数把字串1250.50转换为double类型
如果用户输入一个字符,值将用单引号,如果是字符传将用双引号。用这种技术,用户将被允许使用数字、字符及字符串作为程序的参数来运行程序。

1
为了演示在主函数main()中使用数字参数,改变上例代码如下:
#include
using namespace std;
int main(int argc, char *argv[])
{
double Operand1, Operand2, Addition;

Operand1 = atoi( argv[1] );
Operand2 = atoi( argv[2] );
Addition = Operand1 + Operand2;

cout << "/nFirst Number: " << Operand1;
cout << "/nSecond Number: " << Operand2 << endl;
cout << Operand1 << " + " << Operand2 << " = " << Addition << endl;

return 0;
}

保存文件,关闭VC工程,在命令行下输入CL main.cpp回车,这时生成了新的main.exe程序,再在命令行输入main 48.52 1205回车,你会看到如下运行结果:

----------------------------------------------
D:/MyProgram2/AConsoleApp>main 48.52 1205

First Number: 48
Second Number: 1205
48 + 1205 = 1253

D:/MyProgram2/AConsoleApp>]

-----------------------------------------------------------------

2 为了演示字符串参数情况,改变代码如下:
#include
using namespace std;

int main(int argc, char *argv[])
{
char Sentence[40];
strcpy(Sentence, argv[1]);

cout << "You typed " << Sentence<< endl;
return 0;
}
然后再CL main.cpp编译后输入指令main www.czvc.com回车后有:

---------------------------------------------
D:/MyProgram2/AConsoleApp>main www.czvc.com
You typed www.czvc.com

D:/MyProgram2/AConsoleApp>
-------------------------------------------------------------
3 最后再看一例字串和数字并用的情况,改变代码如下:
#include
using namespace std;

int main(int argc, char *argv[])
{
char FullName[40], strGender[20];
char cGender[10];
float Salary;

strcpy(FullName, argv[1]);
Salary = atof(argv[2]);
strcpy(cGender, argv[3]);

if( cGender == "m" || cGender == "M" )
strcpy(strGender, "Male");
else if( cGender == "f" || cGender == "F" )
strcpy(strGender, "Female");
else
strcpy(strGender, "Unknown Gender");

cout << "Employee Information";
cout << "/nFull Name: " << FullName;
cout << "/nGender: " << strGender;
cout << "/nSalary: " << Salary << endl;
return 0;
}
然后再CL main.cpp编译后输入指令main "WWW.CZVC.COM, LOOMMAN NETWORKS" 18.52 "M"回车后有:

-----------------------------
D:/MyProgram2/AConsoleApp>main "WWW.CZVC.COM, LOOMMAN NETWORKS" 18.52 M
Employee Information
Full Name: WWW.CZVC.COM, LOOMMAN NETWORKS
Gender: Male
Salary: 18.52
-----------------------------------------

posted @ 2012-08-01 16:46 章涛 阅读(217) | 评论 (0)编辑 收藏

NaN错误

NaN,是Not a Number的缩写。   NaN 用于处理计算中出现的错误情况,比如 0.0 除以 0.0 或者求负数的平方根。由上面的表中可以看出,对于单精度浮点数,NaN 表示为指数为 emax + 1 = 128(指数域全为 1),且尾数域不等于零的浮点数。IEEE 标准没有要求具体的尾数域,所以 NaN 实际上不是一个,而是一族。不同的实现可以自由选择尾 数域的值来表达 NaN,比如 Java 中的常量 Float.NaN 的浮点数可能表达为 01111111110000000000000000000000,其中尾数域的第一位为 1,其余均为 0(不计隐藏的一位),但这取决系统的硬件架构。Java 中甚至允许程序员自己构造具有特定位模式的 NaN 值(通过 Float.intBitsToFloat() 方法)。比如,程序员可以利用这种定制的 NaN 值中的特定位模式来表达某些诊断信息。

posted @ 2012-05-11 10:50 章涛 阅读(543) | 评论 (0)编辑 收藏

通配符

通配符是一种特殊语句,主要有星号(*)和问号(?),用来模糊搜索文件。当查找文件夹时,可以使用它来代替一个或多个真正字符;当不知道真正字符或者懒 得输入完整名字时,常常使用通配符代替一个或多个真正的字符。 实际上用“*Not?paOd”可以对应Notpad\MyNotpad【*可以代表任何文字】;Notpad\Notepad【?仅代表单个文 字】;Notepad\Notepod【ao代表a与o里二选一】,其余以此类推。

posted @ 2012-04-26 15:26 章涛 阅读(278) | 评论 (0)编辑 收藏

[精华] 跟我一起写 Makefile

     摘要: 陈皓 概述 —— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一 个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要 了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写...  阅读全文

posted @ 2012-04-26 11:02 章涛 阅读(189) | 评论 (0)编辑 收藏

关于头文件保护符

为什么可以多次包含C++标准库的头文件,是因为每个头文件都已经加了保护符;
我们定义自己的头文件时也要加保护符,使得定义的头文件可以被多次包含。
#ifndef HEAD_H
#define HEAD_H
......
#endif

posted @ 2012-04-19 15:12 章涛 阅读(330) | 评论 (0)编辑 收藏

补充建立自己的头文件:包含多个源文件的编译方法

编译多个源文件组成的代码:
1. 分别编译每个小的源文件,假设我们有:ffmain.cc && fun.cc
g++ -o fmain.o -c ffmian.cc
g++ -o fun.o -c fun.cc
将生成ffmain.o和fun.o两个文件;
2. 连接这两个文件
g++ -o a.out ffmain.o fun.o
将生成最终的a.out文件了。
Contact us

posted @ 2012-04-17 17:11 章涛 阅读(207) | 评论 (0)编辑 收藏

关于分配动态数组的一个注意点

在主函数中定义的

double *p;

请在主函数中动态建立数组

p= new double [];

不要试图通过传递指针P,把建立数组放在子函数中,这样会出错。

如果要想在子函数中建立的话请传递指向指针的引用*&P。

posted @ 2012-04-17 17:03 章涛 阅读(170) | 评论 (0)编辑 收藏

cmath函数列表

cmath是c++语言中的库函数,其中的c表示函数是来自c标准库的函数,math为数学常用库函数。cmath库函数列表:
  using ::abs; //绝对值  using ::acos; //反余弦  using ::acosf; //反余弦  using ::acosl; //反余弦  using ::asin; //反正弦  using ::asinf; //反正弦  using ::asinl; //反正弦  using ::atan; //反正切  using ::atan2; //y/x的反正切  using ::atan2f; //y/x的反正切  using ::atan2l; //y/x的反正切  using ::atanf; //反正切  using ::atanl; //反正切  using ::ceil; //上取整  using ::ceilf; //上取整  using ::ceill; //上取整  using ::cos; //余弦  using ::cosf; //余弦  using ::cosh; //双曲余弦  using ::coshf; //双曲余弦  using ::coshl; //双曲余弦  using ::cosl; //余弦  using ::exp; //指数值  using ::expf; //指数值  using ::expl; //指数值  using ::fabs; //绝对值  using ::fabsf; //绝对值  using ::fabsl; //绝对值  using ::floor; //下取整  using ::floorf; //下取整  using ::floorl; //下取整  using ::fmod; //求余  using ::fmodf; //求余  using ::fmodl; //求余  using ::frexp; //返回value=x*2n中x的值,n存贮在eptr中  using ::frexpf; //返回value=x*2n中x的值,n存贮在eptr中  using ::frexpl; //返回value=x*2n中x的值,n存贮在eptr中  using ::ldexp; //返回value*2exp的值  using ::ldexpf; //返回value*2exp的值  using ::ldexpl; //返回value*2exp的值  using ::log; //对数  using ::log10; //对数  using ::log10f; //对数  using ::log10l; //对数  using ::logf; //对数  using ::logl; //对数  using ::modf; //将双精度数value分解成尾数和阶  using ::modff; //将双精度数value分解成尾数和阶  using ::modfl; //将双精度数value分解成尾数和阶  using ::pow; //计算幂  using ::powf; //计算幂  using ::powl; //计算幂  using ::sin; //正弦  using ::sinf; //正弦  using ::sinh; //双曲正弦  using ::sinhf; //双曲正弦  using ::sinhl; //双曲正弦  using ::sinl; //正弦  using ::sqrt; //开方  using ::sqrtf; //开方  using ::sqrtl; //开方  using ::tan; //正切  using ::tanf; //正切  using ::tanh; //双曲正切  using ::tanhf; //双曲正切  using ::tanhl; //双曲正切  using ::tanl; //正切

posted @ 2012-04-16 09:28 章涛 阅读(1026) | 评论 (0)编辑 收藏

使用 getopt() 进行命令行处理

简介: 所有 UNIX® 程序甚至那些具有图形用户界面(graphical user interface,GUI)的程序,都能接受和处理命令行选项。对于某些程序,这是与其他程序或用户进行交互的主要手段。具有可靠的复杂命令行参数处理 机制,会使得您的应用程序更好、更有用。不过很多开发人员都将其宝贵的时间花在了编写自己的命令行解析器,却不使用 getopt(),而后者是一个专门设计来减轻命令行处理负担的库函数。请阅读本文,以了解如何让 getopt() 在全局结构中记录命令参数,以便随后随时在整个程序中使用。

引言

在早期的 UNIX® 中,其命令行环境(当时的唯一用户界面)包含着数十种小的文本处理工具。这些工具非常小,通常可很好地完成一项工作。这些工具通过较长的命令管道链接在一 起,前面的程序将其输出传递给下一个程序以作为输入,整个过程由各种命令行选项和参数加以控制。

正是 UNIX 的这方面的特征使其成为了极为强大的处理基于本文的数据的环境,而这也是其在公司环境中的最初用途之一。在命令管道的一端输入一些文本,然后在另一端检索经过处理的输出。

命令行选项和参数控制 UNIX 程序,告知它们如何动作。作为开发人员,您要负责从传递给您程序的 main() 函数的命令行发现用户的意图。本文将演示如何使用标准 getopt()getopt_long() 函数来简化命令行处理工作,并讨论了一项用于跟踪命令行选项的技术。

开始之前

本文包含的示例代码(请参见下载)是使用 C 开发工具(C Development Tooling,CDT)在 Eclipse 3.1 中编写的;getopt_demogetopt_long_demo 项目是 Managed Make 项目,均使用 CDT 的程序生成规则构建。在项目中没有包含 Makefile,如果需要在 Eclipse 外编译代码,可以自己方便地生成一个。

如果尚未尝试过 Eclipse(请参阅参考资料),真的应该尝试一下——这是一个优秀的集成开发环境(integrated development environment,IDE),其每个新版本都有较大的提升。这是来自“强硬派” EMACS 和 Makefile 开发人员的作品。

命令行

在编写新程序时,首先遇到的障碍之一就是如何处理控制其行为的命令行参数。这包括从命令行传递给您程序的 main() 函数的一个整数计数(通常名为 argc)和一个指向字符串的指针数组(通常名为 argv).可以采用两种实质一样的方式声明标注 main() 函数,如清单 1 中所示。


清单 1. 声明 main() 函数的两种方式
                 int main( int argc, char *argv[] ); int main( int argc, char **argv ); 

第一种方式使用的是指向 char 指针数组,现在似乎很流行这种方式,比第二种方式(其指针指向多个指向 char 的指针)略微清楚一些。由于某些原因,我使用第二种方式的时间更多一些,这可能源于我在高中时艰难学习 C 指针的经历。对于所有的用途和目的,这两种方法都是一样的,因此可以使用其中您自己最喜欢的方式。

当 C 运行时库的程序启动代码调用您的 main() 时,已经对命令行进行了处理。argc 参数包含参数的计数值,而 argv 包含指向这些参数的指针数组。对于 C 运行时库,arguments 是程序的名称,程序名后的任何内容都应该使用空格加以分隔。

例如,如果使用参数 -v bar www.ibm.com 运行一个名为 foo 程序,您的 argc 将设置为 4,argv 的设置情况将如清单 2 中所示。


清单 2. argv 的内容
                 argv[0] - foo argv[1] - -v argv[2] - bar argv[3] - www.ibm.com 

一个程序仅有一组命令行参数,因此我要将此信息存储在记录选项和设置的全局结构中。对程序有意义的要跟踪的任何内容都可以记录到此结构中,我将使用结构来帮助减少全局变量的数量。正如我在网络服务设计文章(请参阅参考资料)所提到的,全局变量非常不适合用于线程化编程中,因此要谨慎使用。

示例代码将演示一个假想的 doc2html 程序的命令行处理。该 doc2html 程序将某种类型的文档转换为 HTML,具体由用户指定的命令行选项控制。它支持以下选项:

  • -I——不创建关键字索引。
  • -l lang——转换为使用语言代码 lang 指定的语言。
  • -o outfile.html——将经过转换的文档写入到 outfile.html,而不是打印到标准输出。
  • -v——进行转换时提供详细信息;可以多次指定,以提高诊断级别。
  • 将使用其他文件名称来作为输入文档。

您还将支持 -h-?,以打印帮助消息来提示各个选项的用途。

简单命令行处理: getopt()

getopt() 函数位于 unistd.h 系统头文件中,其原型如清单 3 中所示:


清单 3. getopt() 原型
                 int getopt( int argc, char *const argv[], const char *optstring ); 

给定了命令参数的数量 (argc)、指向这些参数的数组 (argv) 和选项字符串 (optstring) 后,getopt() 将返回第一个选项,并设置一些全局变量。使用相同的参数再次调用该函数时,它将返回下一个选项,并设置相应的全局变量。如果不再有识别到的选项,将返回 -1,此任务就完成了。

getopt() 所设置的全局变量包括:

  • optarg——指向当前选项参数(如果有)的指针。
  • optind——再次调用 getopt() 时的下一个 argv 指针的索引。
  • optopt——最后一个已知选项。

对于每个选项,选项字符串 (optstring) 中都包含一个对应的字符。具有参数的选项(如示例中的 -l-o 选项)后面跟有一个 : 字符。示例所使用的 optstringIl:o:vh?(前面提到,还要支持最后两个用于打印程序的使用方法消息的选项)。

可以重复调用 getopt(),直到其返回 -1 为止;任何剩下的命令行参数通常视为文件名或程序相应的其他内容。

getopt() 的使用

让我们对 getopt_demo 项目的代码进行一下深入分析;为了方便起见,我在此处将此代码拆分为多个部分,但您可以在可下载源代码部分获得完整的代码(请参见下载)。

清单 4 中,可以看到系统演示程序所使用的系统头文件;标准 stdio.h 提供标准 I/O 函数原型,stdlib.h 提供 EXIT_SUCCESSEXIT_FAILUREunistd.h 提供 getopt()


清单 4. 系统头文件
                 #include <stdio.h> #include <stdlib.h> #include <unistd.h> 

清单 5 显示了我所创建的 globalArgs 结构,用于以合理的方式存储命令行选项。由于这是个全局变量,程序中任何位置的代码都可以访问这些变量,以确定是否创建关键字索引、生成何种语言等等事项。最好让 main() 函数外的代码将此结构视为一个常量、只读存储区,因为程序的任何部分都可以依赖于其内容。

每个命令行选择都有一个对应的选项,而其他变量用于存储输出文件名、指向输入文件列表的指针和输入文件数量。


清单 5. 全局参数存储和选项字符串
                 struct globalArgs_t {     int noIndex;                /* -I option */     char *langCode;             /* -l option */     const char *outFileName;    /* -o option */     FILE *outFile;     int verbosity;              /* -v option */     char **inputFiles;          /* input files */     int numInputFiles;          /* # of input files */ } globalArgs;  static const char *optString = "Il:o:vh?"; 

选项字符串 optString 告知 getopt() 可以处理哪个选项以及哪个选项需要参数。如果在处期间遇到了其他选项,getopt() 将显示一个错误消息,程序将在显示了使用方法消息后退出。

下面的清单 6 包含一些从 main() 引用的用法消息函数和文档转换函数的小存根。可以对这些存根进行自由更改,以用于更为有用的目的。


清单 6. 存根
                 void display_usage( void ) {     puts( "doc2html - convert documents to HTML" );     /* ... */     exit( EXIT_FAILURE ); }  void convert_document( void ) {     /* ... */ } 

最后,如清单 7 中所示,在 main() 函数中使用此结构。和优秀的开发人员一样,您需要首先初始化 globalArgs 结构,然后才开始处理命令行参数。在您的程序中,可以借此设置在一定情况下合理的缺省值,以便在以后有更合适的缺省值时更方便地对其进行调整。


清单 7. 初始化
                 int main( int argc, char *argv[] ) {     int opt = 0;          /* Initialize globalArgs before we get to work. */     globalArgs.noIndex = 0;     /* false */     globalArgs.langCode = NULL;     globalArgs.outFileName = NULL;     globalArgs.outFile = NULL;     globalArgs.verbosity = 0;     globalArgs.inputFiles = NULL;     globalArgs.numInputFiles = 0; 

清单 8 中的 while 循环和 switch 语句是用于本程序的命令行处理的代码部分。只要 getopt() 发现选项,switch 语句将确定找到的是哪个选项,将能在 globalArgs 结构中看到具体情况。当 getopt() 最终返回 -1 时,就完成了选项处理过程,剩下的都是您的输入文件了。


清单 8. 使用 getopt() 处理 argc/argv
                 opt = getopt( argc, argv, optString );     while( opt != -1 ) {         switch( opt ) {             case 'I':                 globalArgs.noIndex = 1; /* true */                 break;                              case 'l':                 globalArgs.langCode = optarg;                 break;                              case 'o':                 globalArgs.outFileName = optarg;                 break;                              case 'v':                 globalArgs.verbosity++;                 break;                              case 'h':   /* fall-through is intentional */             case '?':                 display_usage();                 break;                              default:                 /* You won't actually get here. */                 break;         }                  opt = getopt( argc, argv, optString );     }          globalArgs.inputFiles = argv + optind;     globalArgs.numInputFiles = argc - optind; 

既然已经完成了参数和选项的收集工作,接下来就可以执行程序所设计的任何功能(在本例中是进行文档转换),然后退出(清单 9)。


清单 9. 开始工作
                 convert_document();          return EXIT_SUCCESS; } 

好,工作完成,非常漂亮。现在就可以不再往下读了。不过,如果您希望程序符合 90 年代末期的标准并支持 GNU 应用程序中流行的 选项,则请继续关注下面的内容。

复杂命令行处理: getopt_long()

在 20 世纪 90 年代(如果没有记错的话),UNIX 应用程序开始支持长选项,即一对短横线(而不是普通 选项所使用的单个短横线)、一个描述性选项名称还可以包含一个使用等号连接到选项的参数。

幸运的是,可以通过使用 getopt_long() 向程序添加长选项支持。您可能已经猜到了,getopt_long() 是同时支持长选项和短选项的 getopt() 版本。

getopt_long() 函数还接受其他参数,其中一个是指向 struct option 对象数组的指针。此结构相当直接,如清单 10 中所示。


清单 10. getopt_long() 的选项
                 struct option {     char *name;     int has_arg;     int *flag;     int val; }; 

name 成员是指向长选项名称(带两个短横线)的指针。has_arg 成员设置为 no_argumentoptional_argument, 或 required_argument(均在 getopt.h 中定义)之一,以指示选项是否具有参数。如果 flag 成员未设置为 NULL,在处理期间遇到此选项时,会使用 val 成员的值填充它所指向的 int 值。如果 flag 成员为 NULL,在 getopt_long() 遇到此选项时,将返回 val 中的值;通过将 val 设置为选项的 short 参数,可以在不添加任何其他代码的情况下使用 getopt_long()——处理 while loopswitch 的现有 getopt() 将自动处理此选项。

这已经变得更为灵活了,因为各个选项现在可以具有可选参数了。更重要的是,仅需要进行很少的工作,就可以方便地放入现有代码中。

让我们看看如何使用 getopt_long() 来对示例程序进行更改(getopt_long_demo 项目可从下载部分获得)。

使用 getopt_long()

由于 getopt_long_demo 几乎与刚刚讨论的 getopt_demo 代码一样,因此我将仅对更改的代码进行说明。由于现在已经有了更大的灵活性,因此还将添加对 --randomize 选项(没有对应的短选项)的支持。

getopt_long() 函数在 getopt.h 头文件(而非 unistd.h)中,因此将需要将该头文件包含进来(请参见清单 11)。我还包含了 string.h,因为将稍后使用 strcmp() 来帮助确定处理的是哪个长参数。


清单 11. 其他头文件
                 #include <getopt.h> #include <string.h> 

您已经为 --randomize 选项在 globalArgs 中添加了一个标志(请参见清单 12),并创建了 longOpts 数组来存储关于此程序支持的长选项的信息。除了 --randomize 外,所有的参数都与现有短选项对应(例如,--no-index 等同于 -I)。通过在选项结构中包含其短选项等效项,可以在不向程序添加任何其他代码的情况下处理等效的长选项。


清单 12. 扩展后的参数
                 struct globalArgs_t {     int noIndex;                /* -I option */     char *langCode;             /* -l option */     const char *outFileName;    /* -o option */     FILE *outFile;     int verbosity;              /* -v option */     char **inputFiles;          /* input files */     int numInputFiles;          /* # of input files */     int randomized;             /* --randomize option */ } globalArgs;  static const char *optString = "Il:o:vh?";  static const struct option longOpts[] = {     { "no-index", no_argument, NULL, 'I' },     { "language", required_argument, NULL, 'l' },     { "output", required_argument, NULL, 'o' },     { "verbose", no_argument, NULL, 'v' },     { "randomize", no_argument, NULL, 0 },     { "help", no_argument, NULL, 'h' },     { NULL, no_argument, NULL, 0 } }; 

清单 13getop() 调用更改为了 getopt_long(),除了 getopt() 的参数外,它还接受 longOpts 数组和 int 指针 (longIndex)。当 getopt_long() 返回 0 时,longIndex 所指向的整数将设置为当前找到的长选项的索引。


清单 13. 新的经改进的选项处理
                 opt = getopt_long( argc, argv, optString, longOpts, &longIndex );     while( opt != -1 ) {         switch( opt ) {             case 'I':                 globalArgs.noIndex = 1; /* true */                 break;                              case 'l':                 globalArgs.langCode = optarg;                 break;                              case 'o':                 globalArgs.outFileName = optarg;                 break;                              case 'v':                 globalArgs.verbosity++;                 break;                              case 'h':   /* fall-through is intentional */             case '?':                 display_usage();                 break;              case 0:     /* long option without a short arg */                 if( strcmp( "randomize", longOpts[longIndex].name ) == 0 ) {                     globalArgs.randomized = 1;                 }                 break;                              default:                 /* You won't actually get here. */                 break;         }                  opt = getopt_long( argc, argv, optString, longOpts, amp;longIndex );     } 

我还添加了 0 的 case,以便处理任何不与现有短选项匹配的长选项。在此例中,只有一个长选项,但代码仍然使用 strcmp() 来确保它是预期的那个选项。

这样就全部搞定了;程序现在支持更为详细(对临时用户更加友好)的长选项。

总结

UNIX 用户始终依赖于命令行参数来修改程序的行为,特别是那些设计作为小工具集合 (UNIX 外壳环境)的一部分使用的实用工具更是如此。程序需要能够快速处理各个选项和参数,且要求不会浪费开发人员的太多时间。毕竟,几乎没有程序设计为仅处理命令行参数,开发人员更应该将精力放在程序所实际进行的工作上。

getopt() 函数是一个标准库调用,可允许您使用直接的 while/switch 语句方便地逐个处理命令行参数和检测选项(带或不带附加的参数)。与其类似的 getopt_long() 允许在几乎不进行额外工作的情况下处理更具描述性的长选项,这非常受开发人员的欢迎。

既然已经知道了如何方便地处理命令行选项,现在就可以集中精力改进您的程序的命令行,可以添加长选项支持,或添加之前由于不想向程序添加额外的命令行选项处理而搁置的任何其他选项。

不要忘记在某处记录您所有的选项和参数,并提供某种类型的内置帮助函数来为健忘的用户提供帮助。

posted @ 2012-04-13 16:32 章涛 阅读(190) | 评论 (0)编辑 收藏

C++ main():处理命令行选项

先简单介绍一下命令行编译C++程序的方法。

编写如下代码,输出参数的个数和各个参数:

[cpp]
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. int main(int argc,char* argv[])  
  4. {  
  5.     printf("argc:%d\n",argc);  
  6.     for(int i = 0;i < argc; ++i)  
  7.     printf("%s\n",argv[i]);  
  8.     system("pause");  
  9. }  
代码中,argc包括命令行选项的个数,argv包含argc个C风格字符串,代表了由空格分隔的命令选项。(程序中可以使用这个为标志来做相应的处理)例如,对于如下命令行:prog -d -o ofile data0,argc被设置为5,且argv被设置为下列C风格字符串:
[cpp]
  1. argv[0] = "prog";  
  2. argv[0] = "-d";  
  3. argv[0] = "-o";  
  4. argv[0] = "ofile";  
  5. argv[0] = "data0";  
aegv[0]总是被设置为当前正在被调用的命令(程序运行生成的exe文件名,不包括扩展名)。从索引1到argc-1表示被传递给命令的实际选项。

命令行编译程序的具体步骤:

先编译运行上述代码,在将生成的exe文件拷贝至C盘目录下(自己设置)。然后打开命令提示符:

输入cd C:\切换工作目录至C盘目录。

再输入prog hust whu whut,运行结果:


下面看一下如何取出在argv中的命令行选项。在例子中,将支持下列用法:

program_name [-d] [-h] [-v] [-o output_file] [-l limit_value]  file_name [file_name [file_name [...]]]。

加括号的内容是可选的。具体步骤见程序:

[cpp] code
  1. //C/C++处理main()函数命令行  
  2. #include <iostream>  
  3. #include <vector>  
  4. #include <string>  
  5. #include <ctype.h>//调用atoi函数  
  6. using namespace std;  
  7.   
  8. const char* const prog_name = "prog";  
  9. const char* const prog_version = "version 1.0 (2011/8/24)";  
  10.   
  11. //退出函数  
  12. inline void usage(int exit_value = 0){  
  13.     cerr<<prog_name<<"  usage!"<<endl;  
  14.     exit(exit_value);  
  15. }  
  16.   
  17. int main(int argc,char* argv[]){  
  18.     //声明用于记录用户指定选项的变量  
  19.     bool debug_on = false;  
  20.     bool ofile_on = false;  
  21.     bool limit_on = false;  
  22.   
  23.     string ofile_name;//记录出现的输出文件名  
  24.     int limit = -1;//限制值  
  25.     vector <string> file_names;//记录文件名  
  26.   
  27.     cout<<"argc:"<<argc<<endl;  
  28.     for(int i = 1;i < argc; ++i){//读取argv中的每个选项  
  29.         //输出第i+1个参量  
  30.         cout<<"argv["<<i<<"]:"<<argv[i]<<endl;  
  31.   
  32.         char *pchar = argv[i];  
  33.         switch(pchar[0]){//确定选项类型:-h,-d,-v,-l,-o;或者其他  
  34.             case '-':{  
  35.                 cout<<"case \'-\' found"<<endl;  
  36.                 switch(pchar[1]){//确定用户指定的选项:h,d,v,l,o  
  37.                     case 'd'://处理调试:  
  38.                         cout<<"-d found:debugging turned on!"<<endl;  
  39.                         debug_on = true;  
  40.                         break;  
  41.                     case 'v'://处理版本请求  
  42.                         cout<<"-v found:version info displayed!"<<endl;  
  43.                         cout<<prog_name<<":"<<prog_version<<endl;  
  44.                         return 0;  
  45.                     case 'h'://处理帮助  
  46.                         cout<<"-h found:help info!"<<endl;  
  47.                         usage();  
  48.                     case 'o'://处理输出文件  
  49.                         cout<<"-o found:output file!"<<endl;  
  50.                         ofile_on = true;  
  51.                         break;  
  52.                     case 'l'://处理限制量  
  53.                         cout<<"-l found:resorce limit!"<<endl;  
  54.                         limit_on = true;  
  55.                         break;  
  56.                     default://无法识别的选项  
  57.                         cerr<<prog_name<<":error:unrecognition option -:"<<pchar<<endl;  
  58.                         usage(-1);  
  59.                 }  
  60.                 break;  
  61.             }  
  62.             default://不以'-'开头,是文件名  
  63.                 if(ofile_on){//输出文件名  
  64.                     cout<<"file name:"<<pchar<<endl;  
  65.                     ofile_name = pchar;  
  66.                     ofile_on = false;//复位  
  67.                 }  
  68.                 else if(limit_on){//限制值  
  69.                     limit_on = false;  
  70.                     limit = atoi(pchar);  
  71.                     if(limit<0){  
  72.                         cerr<<prog_name<<":error:negative value for limit!"<<endl;  
  73.                         usage(-2);  
  74.                     }  
  75.                 }  
  76.                 else{//文件名  
  77.                     file_names.push_back(pchar);  
  78.                 }  
  79.                 break;  
  80.         }  
  81.     }  
  82.     if(file_names.empty()){  
  83.         cerr<<prog_name<<":error:no file for processing!"<<endl;  
  84.         usage(3);  
  85.     }  
  86.     else{  
  87.         cout<<(file_names.size() == 1 ? "File":"Files")<<  
  88.             " to be processed are the followed:"<<endl;  
  89.         for(int i = 0;i < file_names.size();++i){  
  90.             cout<<file_names[i]<<"\t"<<endl;  
  91.         }  
  92.     }  
  93.     if(limit != -1){  
  94.         cout<<"user-specified limit:"<<limit<<endl;  
  95.     }  
  96.     if(!ofile_name.empty()){  
  97.         cout<<"user-specified ofile:"<<ofile_name<<endl;  
  98.     }  
  99.       

posted @ 2012-04-13 14:59 章涛 阅读(596) | 评论 (0)编辑 收藏

仅列出标题
共3页: 1 2 3 
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

导航

统计

常用链接

留言簿

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜