首页 > 学院 > 开发设计 > 正文

使用getopt_long()从命令行获取参数,struct option

2019-11-11 05:05:25
字体:
来源:转载
供稿:网友

本文来自:http://blog.csdn.net/yui/article/details/5669922

函数说明

#include函数说明:函数getopt用来解析命令行参数。函数getopt_long支持长选项的命令行解析。函数原型:intgetopt_long(int argc, char* constargv[],                      const char*optstring,                     const struct option*longopts,                      int*longindex);参数:argc、argv直接从main函数中获取。opting是选项参数组成的字符串,由下列元素组成:1.单个字符,表示选项,2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。3.单个字符后跟两个冒号,表示该选项后可以有参数也可以没有参数。如果有参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。optstring是一个字符串,表示可以接受的参数。例如,"a:b:cd",表示可以接受的参数是a,b,c,d,其中,a和b参数后面跟有更多的参数值。(例如:-ahost -b name)longopts是一个结构的实例:structoption{   constchar *name; //name表示的是长参数名   inthas_arg; //has_arg有3个值,no_argument(或者是0),表示该参数后面不跟参数值              //required_argument(或者是1),表示该参数后面一定要跟个参数值              //optional_argument(或者是2),表示该参数后面可以跟,也可以不跟参数值   int*flag;   //用来决定getopt_long()的返回值是什么。              //flag是null,则函数会返回与该项option匹配的val值。   int val;     //和flag联合决定返回值 };int *flag 如果这个指针为NULL,那么getopt_long()返回该结构val字段中的数值。如果该指针不NULL,getopt_long()会使得它所指向的变量中填入val字段中的数值,并且getopt_long()返回0。如果flag不是NULL,但未发现长选项,那么它所指向的变量的数值不变。int val 这个值是发现了长选项时的返回值,或者flag不是NULL时载入*flag中的值。典型情况下,若flag不是NULL,那么val是个真/假值,譬如1或0;另一方面,如果flag是NULL,那么val通常是字符常量,若长选项与短选项一致,那么该字符常量应该与optstring中出现的这个选项的参数相同。=========================================================================给个例子:struct option long_options[] ={          {"a123", required_argument,0, 'a'},          {"c123", no_argument, 0,'c'},};现在,如果命令行的参数是-a123,那么调用getopt_long()将返回字符'a',并且将字符串123由optarg返回(注意注意!字符串123由optarg带回!optarg不需要定义,在getopt.h中已经有定义)。那么,如果命令行参数是-c,那么调用getopt_long()将返回字符'c',而此时,optarg是null。最后,当getopt_long()将命令行所有参数全部解析完成后,返回-1。===========================================================================以上来自网络,便于学习记忆摘录在这里,下面是自己的理解:函数原型:int getopt_long(intargc, char* const argv[],                      const char*optstring,                     const struct option*longopts,                      int*longindex);其中optstring为单个字符参数,称为short_opts。而longopts为多个字符(即一个或多个单词连接)参数,称为long_opts。参数longindex为longopts数组中的索引返回值。具体用法参考suricata中main()函数中解析命令行参数://短字符参数charshort_opts[] = "c:TDhi:l:q:d:r:us:S:U:VF:";//长字符参数 structoption long_opts[] = {       {"dump-config", 0, &dump_config, 1},  // getopt_long返回值为0,dump_config保存为1       {"pfring", optional_argument, 0, 0},  // getopt_long返回值为0       {"pfring-int", required_argument, 0, 0}, // getopt_long返回值为0,必须有参数       {"pfring-cluster-id", required_argument, 0,0},       {"pfring-cluster-type", required_argument, 0,0},       {"af-packet", optional_argument, 0, 0},       {"pcap", optional_argument, 0, 0},       {"pcap-buffer-size", required_argument, 0,0},       {"unittest-filter", required_argument, 0,'U'},// getopt_long返回值为‘U’,必须有参数       {"list-app-layer-PRotos", 0,&list_app_layer_protocols, 1},       {"list-unittests", 0, &list_unittests,1},       {"list-cuda-cards", 0, &list_cuda_cards,1},       {"list-runmodes", 0, &list_runmodes,1},       {"list-keyWords", optional_argument,&list_keywords, 1},       {"runmode", required_argument, NULL, 0},       {"engine-analysis", 0, &engine_analysis,1},       {"pidfile", required_argument, 0, 0},       {"init-errors-fatal", 0, 0, 0},       {"fatal-unittests", 0, 0, 0},       {"user", required_argument, 0, 0},       {"group", required_argument, 0, 0},       {"erf-in", required_argument, 0, 0},       {"dag", required_argument, 0, 0},       {"napatech", 0, 0, 0},       {"build-info", 0, &build_info, 1},       {NULL, 0, NULL, 0}    };   // 长字符数组索引    intoption_index = 0;  // 以下是用法  while ((opt= getopt_long(argc, argv, short_opts, long_opts,&option_index)) != -1)        switch (opt)        {      // case为函数返回值        case 0:          if(strcmp((long_opts[option_index]).name , "pfring") == 0 ||                                 strcmp((long_opts[option_index]).name , "pfring-int") ==0)                     // TO-DO...                    else if(strcmp((long_opts[option_index]).name , "pcap") ==0)                      // TO-DO...                   break;        case 'c':          break;         case 'T':          break;        default:          usage(argv[0]);           exit(EXIT_FAILURE);      }

函数使用

众所周知,C程序的主函数有两个参数,其中,第一个参数是整型,可以获得包括程序名字的参数个数,第二个参数是字符数组指针或字符指针的指针,可以按顺序获得命令行上各个字符串参数。其原形是:

int main(int argc, char *argv[]);

或者

int main(int argc, char **argv);

 

如果有一个解析CDR的程序,名叫destroy,负责将一个二进制格式的CDR文件转换为文本文件,输出的文本的样式由另外一个描述文件定义,那么,命令行要求输入的参数就有三个:CDR文件名、输出文件名和描述文件名。其中,前两个参数是必须输入的,第三个的描述文件名可以不输入,程序会自动采用默认的输出样式。很自然,主函数的三个参数就应该这样排列:

./destroy cdr cdr.txt [cdr.desc]

 

这样做在一般情况下不会有太大问题,问题来源于扩展性的需求。如果有一天,用户要求解析程序能够按关键字解析,只有含有关键字的CDR才能够输出。解决方法很简单,只要在参数列表的最后,加上它就可以了。不过,这样就使得原本可选的描述文件名变为必须输入:

./destroy cdr cdr.txt cdr.desc [keyword]

 

因为不改的话,你就不知道,第三个参数究竟是描述文件名,还是关键字。现在还算好办,如果以后陆续有增加参数的需求,关键字也变成必须输入了,这个时候,如果要查找全部CDR,你还得定义一个“特殊的关键字”,告诉程序,把数据统统给我捞出来……

 

有鉴于此,在Unix/linux的正式的项目上,程序员通常会使用getopt()或者getopt_long()来获得输入的参数。两者的一个区别在于getopt()只支持短格式参数,而getopt_long()既支持短格式参数,又支持长格式参数。

短格式:./destroy -f cdr -o cdr.txt -c cdr.desc -k 123456

长格式:./destroy --file cdr --output cdr.txt --config cdr.desc --keyword 123456

 

引入了getopt()和getopt_long()的项目,设计者可以按需要,方便地增加参数,或者随意地放置参数的先后次序,只需要在程序中判断,哪些参数是必须的就可以了。关于这两个函数的用法,大家可以上网搜索一下,不再累述。附件destroy_linux.c给出了在Linux下使用getopt_long()的实例。

[cpp] view plaincopy#include <stdio.h>  #include <stdlib.h>  #include <unistd.h>  #include <getopt.h>    void print_usage(const char *program_name) {      printf("%s 1.0.0 (2010-06-13)/n", program_name);      printf("This is a program decoding a BER encoded CDR file/n");      printf("Usage: %s -f <file_name> -o <output_name> [-c <config_name>] [-k <keyword>]/n", program_name);      printf("    -f --file       the CDR file to be decoded/n");      printf("    -o --output     the output file in plain text format/n");      printf("    -c --config     the description file of the CDR file, if not given, use default configuration/n");      printf("    -k --keyword    the keyword to search, if not given, all records will be written into output file/n");  }    int main(int argc, char *argv[]) {      char *file_name = NULL;      char *output_name = NULL;      char *config_name = NULL;      char *keyword = NULL;        const char *short_opts = "hf:o:c:k:";      const struct option long_opts[] = {          {"help", no_argument, NULL, 'h'},          {"file", required_argument, NULL, 'f'},          {"output", required_argument, NULL, 'o'},          {"config", required_argument, NULL, 'c'},          {"keyword", required_argument, NULL, 'k'},          {0, 0, 0, 0}      };      int hflag = 0;        int c;      opterr = 0;        while ( (c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1 ) {          switch ( c ) {              case 'h' :                  hflag = 1;                  break;              case 'f' :                  file_name = optarg;                  break;              case 'o' :                  output_name = optarg;                  break;              case 'c' :                  config_name = optarg;                  break;              case 'k' :                  keyword = optarg;                  break;              case '?' :                  if ( optopt == 'f' || optopt == 'o' || optopt == 'c' || optopt == 'k' )                      printf("Error: option -%c requires an argument/n", optopt);                  else if ( isprint(optopt) )                      printf("Error: unknown option '-%c'/n", optopt);                  else                      printf("Error: unknown option character '//x%x'/n", optopt);                  return 1;              default :                  abort();          }      }        if ( hflag || argc == 1 ) {          print_usage(argv[0]);          return 0;      }      if ( !file_name ) {          printf("Error: file name must be specified/n");          return 1;      }      if ( !output_name ) {          printf("Error: output name must be specified/n");          return 1;      }        // if not setting default, Linux OK, but SunOS core dump      if ( !config_name ) config_name = "(null)";      if ( !keyword ) keyword = "(null)";      printf("Parameters got: file_name = %s, output_name = %s, config_name = %s, keyword = %s/n", file_name, output_name, config_name, keyword);      return 0;  }  

 

另外一个区别是,getopt()几乎通用于所有类Unix系统,而getopt_long()只有在GNU的Unix/Linux下才能用。如果把上述程序放到Tru64上编译,就会出现以下错误:

cc -o destroy destroy_linux.c

cc: Error: destroy_linux.c, line 24: In the initializer for long_opts, an array's element type is incomplete, which precludes its initialization. (incompelinit)

                {"help", no_argument, NULL, 'h'},

----------------^

 

所以,如果一定要在Tru64等非GNU的OS上做到长格式的效果,除了自己另起炉灶之外,基本上只好借助一些跨平台的开源项目了。附件里的getopt_long.c和getopt.h是从opensolaris的网站上抄下来的,是包含在sg3_utils软件包中的程序。sg3_utils具体是什么,我也不知道,据说是一个Linux的开发包,用来直接使用SCSI命令集访问设备。(sg3_utils is a package of utilities for accessing devices that use SCSI command sets.)反正拿来能用就是了!

[cpp] view plaincopy/*  $NetBSD: getopt.h,v 1.7 2005/02/03 04:39:32 perry Exp $ */    /*-  * Copyright (c) 2000 The NetBSD Foundation, Inc.  * All rights reserved.  *  * This code is derived from software contributed to The NetBSD Foundation  * by Dieter Baron and Thomas Klausner.  *  * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions  * are met:  * 1. Redistributions of source code must retain the above copyright  *    notice, this list of conditions and the following disclaimer.  * 2. Redistributions in binary form must reproduce the above copyright  *    notice, this list of conditions and the following disclaimer in the  *    documentation and/or other materials provided with the distribution.  * 3. All advertising materials mentioning features or use of this software  *    must display the following acknowledgement:  *        This product includes software developed by the NetBSD  *        Foundation, Inc. and its contributors.  * 4. Neither the name of The NetBSD Foundation nor the names of its  *    contributors may be used to endorse or promote products derived  *    from this software without specific prior written permission.  *  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  * POSSIBILITY OF SUCH DAMAGE.  */    /*  * modified May 12, 2005 by Jim Basney <jbasney@ncsa.uiuc.edu>  *  * removed #include of non-POSIX <sys/cdefs.h> and <sys/featuretest.h>  * removed references to _NETBSD_SOURCE and HAVE_NBTOOL_CONFIG_H  * added #if !HAVE_GETOPT_LONG  * removed __BEGIN_DECLS and __END_DECLS  */    #ifndef _MYPROXY_GETOPT_H_  #define _MYPROXY_GETOPT_H_    #if !HAVE_GETOPT_LONG    #include <unistd.h>    /*  * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions  */  #define no_argument        0  #define required_argument  1  #define optional_argument  2    extern char *optarg;  extern int optind;  extern int optopt;  extern int opterr;    struct option {      /* name of long option */      const char *name;      /*      * one of no_argument, required_argument, and optional_argument:      * whether option takes an argument      */      int has_arg;      /* if not NULL, set *flag to val when option found */      int *flag;      /* if flag not NULL, value to set *flag to; else return value */      int val;  };    int getopt_long(int, char * const *, const char *,      const struct option *, int *);     #endif /* !HAVE_GETOPT_LONG */    #endif /* !_MYPROXY_GETOPT_H_ */  [cpp] view plaincopy/*  $NetBSD: getopt_long.c,v 1.17 2004/06/20 22:20:15 jmc Exp $ */    /*-  * Copyright (c) 2000 The NetBSD Foundation, Inc.  * All rights reserved.  *  * This code is derived from software contributed to The NetBSD Foundation  * by Dieter Baron and Thomas Klausner.  *  * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions  * are met:  * 1. Redistributions of source code must retain the above copyright  *    notice, this list of conditions and the following disclaimer.  * 2. Redistributions in binary form must reproduce the above copyright  *    notice, this list of conditions and the following disclaimer in the  *    documentation and/or other materials provided with the distribution.  * 3. All advertising materials mentioning features or use of this software  *    must display the following acknowledgement:  *        This product includes software developed by the NetBSD  *        Foundation, Inc. and its contributors.  * 4. Neither the name of The NetBSD Foundation nor the names of its  *    contributors may be used to endorse or promote products derived  *    from this software without specific prior written permission.  *  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  * POSSIBILITY OF SUCH DAMAGE.  */    /*  * modified May 12, 2005 by Jim Basney <jbasney@ncsa.uiuc.edu>  *  * removed #include of non-POSIX <sys/cdefs.h> <err.h>  * removed #include of "namespace.h"  * use local "port_getopt.h" instead of <getopt.h>  * removed REPLACE_GETOPT and HAVE_NBTOOL_CONFIG_H sections  * removed __P() from function declarations  * use ANSI C function parameter lists  * removed optreset support  * replace _DIAGASSERT() with assert()  * replace non-POSIX warnx(...) with fprintf(stderr, ...)  * added extern declarations for optarg, optind, opterr, and optopt  */    #if defined(LIBC_SCCS) && !defined(lint)  __RCSID("$NetBSD: getopt_long.c,v 1.17 2004/06/20 22:20:15 jmc Exp $");  #endif /* LIBC_SCCS and not lint */    #include <assert.h>  #include <errno.h>  #include "getopt.h"  #include <stdio.h>  #include <stdlib.h>  #include <string.h>    #ifdef __weak_alias  __weak_alias(getopt_long,_getopt_long)  #endif    #if !HAVE_GETOPT_LONG  #define IGNORE_FIRST    (*options == '-' || *options == '+')  #define PRINT_ERROR ((opterr) && ((*options != ':') /                        || (IGNORE_FIRST && options[1] != ':')))  #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)  #define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)  /* XXX: GNU ignores PC if *options == '-' */  #define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')    /* return values */  #define BADCH   (int)'?'  #define BADARG      ((IGNORE_FIRST && options[1] == ':') /               || (*options == ':') ? (int)':' : (int)'?')  #define INORDER (int)1    #define EMSG    ""    extern char *optarg;  extern int optind, opterr, optopt;    static int getopt_internal (int, char * const *, const char *);  static int gcd (int, int);  static void permute_args (int, int, int, char * const *);    static char *place = EMSG; /* option letter processing */    static int nonopt_start = -1; /* first non option argument (for permute) */  static int nonopt_end = -1;   /* first option after non options (for permute) */    /* Error messages */  static const char recargchar[] = "option requires an argument -- %c";  static const char recargstring[] = "option requires an argument -- %s";  static const char ambig[] = "ambiguous option -- %.*s";  static const char noarg[] = "option doesn't take an argument -- %.*s";  static const char illoptchar[] = "unknown option -- %c";  static const char illoptstring[] = "unknown option -- %s";      /*  * Compute the greatest common divisor of a and b.  */  static int  gcd(int a, int b)  {      int c;        c = a % b;      while (c != 0) {          a = b;          b = c;          c = a % b;      }               return b;  }    /*  * Exchange the block from nonopt_start to nonopt_end with the block  * from nonopt_end to opt_end (keeping the same order of arguments  * in each block).  */  static void  permute_args(int panonopt_start, int panonopt_end, int opt_end,           char * const *nargv)  {      int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;      char *swap;        assert(nargv != NULL);        /*      * compute lengths of blocks and number and size of cycles      */      nnonopts = panonopt_end - panonopt_start;      nopts = opt_end - panonopt_end;      ncycle = gcd(nnonopts, nopts);      cyclelen = (opt_end - panonopt_start) / ncycle;        for (i = 0; i < ncycle; i++) {          cstart = panonopt_end+i;          pos = cstart;          for (j = 0; j < cyclelen; j++) {              if (pos >= panonopt_end)                  pos -= nnonopts;              else                  pos += nopts;              swap = nargv[pos];              /* LINTED const cast */              ((char **) nargv)[pos] = nargv[cstart];              /* LINTED const cast */              ((char **)nargv)[cstart] = swap;          }      }  }    /*  * getopt_internal --  *  Parse argc/argv argument vector.  Called by user level routines.  *  Returns -2 if -- is found (can be long option or end of options marker).  */  static int  getopt_internal(int nargc, char * const *nargv, const char *options)  {      char *oli;              /* option letter list index */      int optchar;        assert(nargv != NULL);      assert(options != NULL);        optarg = NULL;        /*      * XXX Some programs (like rsyncd) expect to be able to      * XXX re-initialize optind to 0 and have getopt_long(3)      * XXX properly function again.  Work around this braindamage.      */      if (optind == 0)          optind = 1;    start:      if (!*place) {                      /* update scanning pointer */          if (optind >= nargc) {          /* end of argument vector */              place = EMSG;              if (nonopt_end != -1) {                  /* do permutation, if we have to */                  permute_args(nonopt_start, nonopt_end,                      optind, nargv);                  optind -= nonopt_end - nonopt_start;              }              else if (nonopt_start != -1) {                  /*                  * If we skipped non-options, set optind                  * to the first of them.                  */                  optind = nonopt_start;              }              nonopt_start = nonopt_end = -1;              return -1;          }          if ((*(place = nargv[optind]) != '-')              || (place[1] == '/0')) {    /* found non-option */              place = EMSG;              if (IN_ORDER) {                  /*                  * GNU extension:                   * return non-option as argument to option 1                  */                  optarg = nargv[optind++];                  return INORDER;              }              if (!PERMUTE) {                  /*                  * if no permutation wanted, stop parsing                  * at first non-option                  */                  return -1;              }              /* do permutation */              if (nonopt_start == -1)                  nonopt_start = optind;              else if (nonopt_end != -1) {                  permute_args(nonopt_start, nonopt_end,                      optind, nargv);                  nonopt_start = optind -                      (nonopt_end - nonopt_start);                  nonopt_end = -1;              }              optind++;              /* process next argument */              goto start;          }          if (nonopt_start != -1 && nonopt_end == -1)              nonopt_end = optind;          if (place[1] && *++place == '-') {  /* found "--" */              place++;              return -2;          }      }      if ((optchar = (int)*place++) == (int)':' ||          (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {          /* option letter unknown or ':' */          if (!*place)              ++optind;          if (PRINT_ERROR)              fprintf(stderr, illoptchar, optchar);          optopt = optchar;          return BADCH;      }      if (optchar == 'W' && oli[1] == ';') {      /* -W long-option */          /* XXX: what if no long options provided (called by getopt)? */          if (*place)               return -2;            if (++optind >= nargc) { /* no arg */              place = EMSG;              if (PRINT_ERROR)                  fprintf(stderr, recargchar, optchar);              optopt = optchar;              return BADARG;          } else              /* white space */              place = nargv[optind];          /*          * Handle -W arg the same as --arg (which causes getopt to          * stop parsing).          */          return -2;      }      if (*++oli != ':') {            /* doesn't take argument */          if (!*place)              ++optind;      } else {                /* takes (optional) argument */          optarg = NULL;          if (*place)         /* no white space */              optarg = place;          /* XXX: disable test for :: if PC? (GNU doesn't) */          else if (oli[1] != ':') {   /* arg not optional */              if (++optind >= nargc) { /* no arg */                  place = EMSG;                  if (PRINT_ERROR)                      fprintf(stderr, recargchar, optchar);                  optopt = optchar;                  return BADARG;              } else                  optarg = nargv[optind];          }          place = EMSG;          ++optind;      }      /* dump back option letter */      return optchar;  }    /*  * getopt_long --  *  Parse argc/argv argument vector.  */  int  getopt_long(int nargc, char * const *nargv, const char *options,          const struct option *long_options, int *idx)  {      int retval;        assert(nargv != NULL);      assert(options != NULL);      assert(long_options != NULL);      /* idx may be NULL */        if ((retval = getopt_internal(nargc, nargv, options)) == -2) {          char *current_argv, *has_equal;          size_t current_argv_len;          int i, match;            current_argv = place;          match = -1;            optind++;          place = EMSG;            if (*current_argv == '/0') {        /* found "--" */              /*              * We found an option (--), so if we skipped              * non-options, we have to permute.              */              if (nonopt_end != -1) {                  permute_args(nonopt_start, nonopt_end,                      optind, nargv);                  optind -= nonopt_end - nonopt_start;              }              nonopt_start = nonopt_end = -1;              return -1;          }          if ((has_equal = strchr(current_argv, '=')) != NULL) {              /* argument found (--option=arg) */              current_argv_len = has_equal - current_argv;              has_equal++;          } else              current_argv_len = strlen(current_argv);                    for (i = 0; long_options[i].name; i++) {              /* find matching long option */              if (strncmp(current_argv, long_options[i].name,                  current_argv_len))                  continue;                if (strlen(long_options[i].name) ==                  (unsigned)current_argv_len) {                  /* exact match */                  match = i;                  break;              }              if (match == -1)        /* partial match */                  match = i;              else {                  /* ambiguous abbreviation */                  if (PRINT_ERROR)                      fprintf(stderr, ambig, (int)current_argv_len,                           current_argv);                  optopt = 0;                  return BADCH;              }          }          if (match != -1) {          /* option found */                  if (long_options[match].has_arg == no_argument                  && has_equal) {                  if (PRINT_ERROR)                      fprintf(stderr, noarg, (int)current_argv_len,                           current_argv);                  /*                  * XXX: GNU sets optopt to val regardless of                  * flag                  */                  if (long_options[match].flag == NULL)                      optopt = long_options[match].val;                  else                      optopt = 0;                  return BADARG;              }              if (long_options[match].has_arg == required_argument ||                  long_options[match].has_arg == optional_argument) {                  if (has_equal)                      optarg = has_equal;                  else if (long_options[match].has_arg ==                      required_argument) {                      /*                      * optional argument doesn't use                      * next nargv                      */                      optarg = nargv[optind++];                  }              }              if ((long_options[match].has_arg == required_argument)                  && (optarg == NULL)) {                  /*                  * Missing argument; leading ':'                  * indicates no error should be generated                  */                  if (PRINT_ERROR)                      fprintf(stderr, recargstring, current_argv);                  /*                  * XXX: GNU sets optopt to val regardless                  * of flag                  */                  if (long_options[match].flag == NULL)                      optopt = long_options[match].val;                  else                      optopt = 0;                  --optind;                  return BADARG;              }          } else {            /* unknown option */              if (PRINT_ERROR)                  fprintf(stderr, illoptstring, current_argv);              optopt = 0;              return BADCH;          }          if (long_options[match].flag) {              *long_options[match].flag = long_options[match].val;              retval = 0;          } else               retval = long_options[match].val;          if (idx)              *idx = match;      }      return retval;  }  #endif /* !GETOPT_LONG */  

 

拿过来后,把他们放到与destroy_linux.c同一目录下,只需要把destroy_linux.c的头文件改一个地方,#include <getopt.h>改为#include “getopt.h”,就能够编译运行了。而且,这样改好后,不仅在Tru64上能运行,在Linux、SunOS上也能运行。

[cpp] view plaincopy#include <stdio.h>  #include <stdlib.h>  #include <unistd.h>  #include "getopt.h"    void print_usage(const char *program_name) {      printf("%s 1.0.0 (2010-06-13)/n", program_name);      printf("This is a program decoding a BER encoded CDR file/n");      printf("Usage: %s -f <file_name> -o <output_name> [-c <config_name>] [-k <keyword>]/n", program_name);      printf("    -f --file       the CDR file to be decoded/n");      printf("    -o --output     the output file in plain text format/n");      printf("    -c --config     the description file of the CDR file, if not given, use default configuration/n");      printf("    -k --keyword    the keyword to search, if not given, all records will be written into output file/n");  }    int main(int argc, char *argv[]) {      char *file_name = NULL;      char *output_name = NULL;      char *config_name = NULL;      char *keyword = NULL;        const char *short_opts = "hf:o:c:k:";      const struct option long_opts[] = {          {"help", no_argument, NULL, 'h'},          {"file", required_argument, NULL, 'f'},          {"output", required_argument, NULL, 'o'},          {"config", required_argument, NULL, 'c'},          {"keyword", required_argument, NULL, 'k'},          {0, 0, 0, 0}      };      int hflag = 0;        int c;      opterr = 0;        while ( (c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1 ) {          switch ( c ) {              case 'h' :                  hflag = 1;                  break;              case 'f' :                  file_name = optarg;                  break;              case 'o' :                  output_name = optarg;                  break;              case 'c' :                  config_name = optarg;                  break;              case 'k' :                  keyword = optarg;                  break;              case '?' :                  if ( optopt == 'f' || optopt == 'o' || optopt == 'c' || optopt == 'k' )                      printf("Error: option -%c requires an argument/n", optopt);                  else if ( isprint(optopt) )                      printf("Error: unknown option '-%c'/n", optopt);                  else                      printf("Error: unknown option character '//x%x'/n", optopt);                  return 1;              default :                  abort();          }      }        if ( hflag || argc == 1 ) {          print_usage(argv[0]);          return 0;      }      if ( !file_name ) {          printf("Error: file name must be specified/n");          return 1;      }      if ( !output_name ) {          printf("Error: output name must be specified/n");          return 1;      }        // if not setting default, Linux OK, but SunOS core dump      if ( !config_name ) config_name = "(null)";      if ( !keyword ) keyword = "(null)";      printf("Parameters got: file_name = %s, output_name = %s, config_name = %s, keyword = %s/n", file_name, output_name, config_name, keyword);      return 0;  }  

 

Linux下编译

-bash-3.2$ gcc -o destroy destroy.c getopt_long.c

短格式,全部输入

-bash-3.2$ ./destroy -f aaa -o aaa.txt -c ccc -k 222

Parameters got: file_name = aaa, output_name = aaa.txt, config_name = ccc, keyword = 222

前两个长格式,后两个短格式

-bash-3.2$ ./destroy --file aaa --output aaa.txt -c ccc -k 222

Parameters got: file_name = aaa, output_name = aaa.txt, config_name = ccc, keyword = 222

漏掉一个必须输入的参数会报错

-bash-3.2$ ./destroy -output aaa.txt

Error: file name must be specified

次序随意,长短混用

-bash-3.2$ ./destroy -c ccc -o aaa.txt -k 222 --file aaa

Parameters got: file_name = aaa, output_name = aaa.txt, config_name = ccc, keyword = 222

 

题外话,#include <filename.h>与#include “filename.h”有什么区别,是面试C程序员经常问到的一个问题。答案大家都知道了,#include <filename.h>,编译器从标准库路径搜索filename.h,而#include “filename.h”,编译器从用户的工作路径搜索filename.h。

 

此外,网上也有人说从glibc(http://sourceware.org/glibc/)上把getopt.h、getopt.c和getoptl.c拿过来也能够用。我也试过,但是不清楚什么原因不成功。

 

在这个小实验的过程中,还发现了C语言在各个OS下的一些细小差异,比如destroy.c里,79行到82行:

// if not setting default, Linux OK, but SunOS core dump

if ( !config_name ) config_name = "(null)";

if ( !keyword ) keyword = "(null)";

printf("Parameters got: file_name = %s, output_name = %s, config_name = %s, keyword = %s/n", file_name, output_name, config_name, keyword);

 

如果在81行和82行不设置空指针的默认值,Linux和Tru64都会自动帮你转换而避免运行时错误,但是SunOS不会,它会死给你看。

./destroy -f aaa -o aaa.txt

Segmentation Fault (core dumped)

 

再比如第62行的abort()在头文件stdlib.h中定义,如果不包含此文件,SunOS与Tru64编译都没问题,Linux编译时会警告:

warning: incompatible implicit declaration of built-in function abort

 

由此看来,虽然C也公认是可移植性比较好的语言,但是在跨平台的项目中,也应该注意这些微小的差别。

转自:http://blog.csdn.net/lanmanck/article/details/11999345


上一篇:yang模型理解

下一篇:几个小总结

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表