文章目录
程序参数
许多命令行运行的C程序都会有可选(或必须要有)的参数,如 gcc prog.c -o prog,“prog.c”、"-o"、"prog"这些都是参数。
参数中有些会被称为选项(标志、开关),选项参数(options)往往被用作调整程序的功能,比如 -o 就是gcc的一个选项,它可以指定输出文件的名字(默认的输出文件名为a.out);而另外的一些参数当然就是非选项参数了。
命令行在LINUX/UNIX中一般都会遵守一些准则,在X/Open规范中可以找到详细具体的内容。下面是一些常见且简单的描述:
- 单字符选项参数一般要加一个短横杠( - ),也就是减号。如,gcc命令中的 -o
- 长选项参数一般要加双短横杠( – ),就是两个连续的减号。如, gcc --help 、 node --version (很多命令行都会有这两个选项,help用于查看手册、version用于查看版本)
- 参数之间要用空格隔开。如果一个参数中包含了空白字符,就需要用双引号把整个参数闭合起来。如, Hello World 表示两个参数(一个Hello、一个World);而 “Hello World” 则代表的是一个参数。
*注:并不是所有的命令行都遵守了这个准则
简单的带参数示例
要编写带参数的C程序就需要给main函数传入两个参数:int argc、char *argv[] .
前者是一个整型参数,代表着一条命令行中字符串的个数(字符串之间用空格隔开,含有空格的字符串要用双引号闭合,这个和上面说过的一样);后者是一个数组,存放着指向每个字符串的指针。
以一条命令 $ myecho hello world ! 为例($代表的是命令提示符,这个应该很清楚它不是命令的一部分),如下图所示:
当运行这条命令时,argc就被赋值为4,而argv[]就会存放各个字符串的指针。
需要注意的是:
- argv[]存放的是指针,而不是字符
- 虽然myecho是程序文件的名称而非参数,但它确实是命令的一部分,字符串的个数要算上它!所以argc是4而非3
如此一个带参数的C程序大致如下所示:
int main(int argc, char *argv[])
{
//...CODE...
return 0;
}
一个简单的示例:
//FILENAME: myprogram.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int arg = 0;
while(arg < argc)
{
printf("%s\n", argv[arg]);
arg++;
}
printf("argc = %d\n", argc);
exit(0);
}
运行结果1
$ ./myprogram hello world !
./myprogram
hello
world
!
argc = 4
$
运行结果2
$ ./myprogram "hello world" !
./myprogram
hello world
!
argc = 3
$
getopt函数
为了方便编写遵守一定命令行准则的程序,Linux提供了getopt函数,其原型如下:
#include <unistd.h>
int getopt(int agrc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
>> 关于getopt的参数
getopt函数的参数有三个:
- argc 和 argv : getopt将传递给main函数的argc和argv作为参数。
- const char *optstring :一个字符串,其中的每一个字符代表着一个单字符选项(即用户只能使用这些选项)。
对于optstring参数:
-
如,该字符串参数为"abcd",则表示有四个选项参数:-a、-b、-c、-d
-
如果一个字符后面跟着一个冒号( : ),则表示该选项参数后面必须有一个关联值。如字符串参数为"f:h",则表示有两个选项参数:-f、-h ,但是 -f 后面必须有一个关联值,比如一个文件名。
-
以命令 gcc prog.c -o prog为例, -o 表示一个选项参数,而非选项参数 prog 就是它的一个关联值。
>> 关于getopt的返回值及一些行为
-
getopt的返回值是argv数组中的下一个选项字符(循环调用getopt可遍历所有选项),如果不存在则返回-1
-
如果选项参数有一个关联值,则外部指针变量optarg将指向该关联值。(注意在getopt函数的原型中列出了一些外部变量)
-
如果遇到一个无法识别的选项字符(即该字符不存在于字符串参数optstring中),则getopt会返回一个问号( ? ),并且这个无法识别的字符会被保存至外部变量optopt中。
-
如果一个选项参数要求一个关联值参数,但用户并没有提供,则getopt也会返回一个问号,并将这个选项参数保存至外部变量optopt中;但是如果字符串参数optstring中的第一个字符是一个冒号( : ),那么这种情况下getopt将不会返回问好,而是返回一个冒号。
>> getopt函数的简单示例
//FILENAME: getoptdemo.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int opt;
while((opt = getopt(argc, argv, ":f:h")) != -1)
{
switch(opt){
case 'f':
printf("FILENAME: %s\n", optarg);
break;
case 'h':
printf("This is a demo.\n");
break;
case '?':
printf("ERROR: unrecognized command line option ‘-%c’\n", optopt);
break;
case ':':
printf("‘-%c’ needs a value\n", optopt);
break;
}
}
exit(0);
}
运行结果1
$ ./optdemo -f
‘-f’ needs a value
$
运行结果2
$ ./optdemo -h
This is a demo.
$
运行结果3
$ ./optdemo -f demo.c
FILENAME: demo.c
$
运行结果4
$ ./optdemo -x
ERROR: unrecognized command line option ‘-x’
$
运行结果5
$ ./optdemo -f demo.c -h
FILENAME: demo.c
This is a demo.
$
getopt_long函数
如果要让程序能够使用长选项参数,可以使用getopt_long函数(使用该函数,原来的单字符选项参数依然可以使用)。
>> getopt_long的简单示例
因为getopt_long的用法与getopt差不多,所以先直接给一个示例:
//FILENAME: longoptdemo.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define _GNU_SOURCE
#include <getopt.h>
int main(int argc, char **argv)
{
int opt;
struct option longopts[] = {
{"help", 0, NULL, 'h'},
{"file", 1, NULL, 'f'},
{0, 0, 0, 0}
};
while((opt = getopt_long(argc, argv, ":hf:", longopts, NULL)) != -1)
{
switch(opt){
case 'f':
printf("FILENAME: %s\n", optarg);
break;
case 'h':
printf("This is a demo.\n");
break;
case '?':
printf("ERROR: unrecognized command line option ‘-%c’\n", optopt);
break;
case ':':
printf("‘-%c’ needs a value\n", optopt);
break;
}
}
exit(0);
}
该示例与getopt示例的功能基本一样,另外getopt_long函数的前三个参数和getopt的三个函数完全一模一样。第四个参数是一个结构数组,第五个参数是一个变量指针。
该结构数组下面将提到,而变量指针相当于长选项参数版的optind(这里并没有用到它,所以设为NULL)。
>> struct option结构
getopt_long函数的第四个参数是一个结构数组,数组中的每个元素都是一个 struct option 结构。
这个结构用于描述一个长选项参数,它被定义在头文件 getopt.h 中,并且还要将常量 _GNU_SOURCE 一同包含进来才能使用getopt功能(见源文件的预处理部分)。
该结构的定义如下所示:
struct option{
const char *name;
int has_arg;
int *flag;
int val;
};
各成员的含义如下:
成员变量 | 说明 |
---|---|
name | 长选项的名字 |
has_arg | 用于表示该选项是否带参数(可以理解为之前的关联值)。0表示不带参数、1表示必须带一个参数、2表示可以带一个参数 |
flag | 若flag为NULL,则表示当getopt_long扫描到一个长选项参数时,将返回成员变量val的值; 若flag不为NULL,则表示当get_long扫描到一个长选项参数时,将返回0,并将成员变量val的值写入flag所指向的变量 |
val | 一个长选项结构要设置一个对应的值val,其用途为上面flag变量中所述 |
最后还需要注意一点: 长选项结构数组的最后一个元素必须是 {0, 0, 0, 0}
>> 运行结果
运行结果1
$ ./longoptdemo --help
This is a demo.
$
运行结果2
$ ./longoptdemo -h
This is a demo.
$
运行结果3
$ ./longoptdemo --file demo.c
FILENAME: demo.c
$
运行结果4
$ ./longoptdemo -x
ERROR: unrecognized command line option ‘-x’
$
注
* 该笔记并没有说明两个外部变量(optind、opterr)的作用,另外示例程序也有一些不合理的地方