使用getopt_long()從命令列獲取引數,struct option
函式說明
函式使用
眾所周知,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()的例項。
- #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.)反正拿來能用就是了!
- /* $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_ */
- /* $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上也能執行。
- #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/yui/article/details/5669922相關文章
- 使用getopt_long()從命令列獲取引數命令列
- 命令列引數解析函式getopt_long() 使用詳解命令列函式
- linux的命令列解析引數之getopt_long函式使用Linux命令列函式
- linux 中解析命令列引數 (getopt_long用法)Linux命令列
- 命令列引數選項處理:getopt()及getopt_long()函式使用命令列函式
- python獲取命令列引數的程式碼Python命令列
- 一個使用getopt()函式獲取命令列引數的例子(轉)函式命令列
- vue獲取位址列引數方法Vue
- js獲取位址列的引數JS
- 1.linux的命令列解析引數之getopt_long函式Linux命令列函式
- TCL指令碼讀取命令列引數指令碼命令列
- Rust 程式設計,讀取命令列引數Rust程式設計命令列
- java 使用命令列引數(轉)Java命令列
- 使用argparse模組新增命令列引數命令列
- 如何從context-param獲取引數?Context
- 超簡潔的js獲取位址列引數JS
- Vue獲取位址列引數並做改變Vue
- 命令列引數解析模組argparse的使用命令列
- 從已執行容器獲取 docker run 引數Docker
- 正規表示式獲取位址列傳遞引數
- php全面獲取url位址列及各種引數PHP
- PHP全面獲取url位址列引數多種方法PHP
- JavaScript—獲取引數(23)JavaScript
- 常用操作 / 獲取引數
- js獲取url引數JS
- jquery獲取url引數jQuery
- C++ main函式命令列引數使用C++AI函式命令列
- Logstash 命令列引數命令列
- 命令列引數 opencv呼叫命令列OpenCV
- Go 接收命令列引數Go命令列
- js獲取url傳遞引數,js獲取url?號後面的引數JS
- 獲取位址列引數 - queryString(正規表示式版本)
- 使用jquery獲取url及url引數的方法jQuery
- Laravel request 獲取路由引數Laravel路由
- oracle獲取隱含引數Oracle
- jQuery獲取url引數值jQuery
- Js獲取URL地址引數JS
- 獲取位址列url連結?後面傳遞的引數