每个 C 语言程序都必须有一个称为 main()的函数,作为程序启动的起点。当执行程序时,
命令行参数(command-line argument)(由 shell 逐一解析)通过两个入参提供给 main()函数。
int main(int argc, char *argv[]);
- 第一个参数 int argc,表示命令行参数的个数。
-
第二个参数 char *argv[],是一个指向命令行参数的指针数组:
- 每一参数又都是以空字符(null)结尾的字符串。
- 首个字符串 argv[0],标识程序名本身
- argv 中的指针列表以 NULL 指针结尾(即 argv[argc]为 NULL)
argv[0]包含了调用程序的名称,可以利用这一特性玩个使用的小技巧。首先为同一程序创建多个链接(即名称不同),然后让该程序查看argv[0],并根据调用程序的名称来执行不同任务。gzip(1)、gunzip(1)和 zcat(1)命令是该技术应用的一个例子,这些命令链接的都是同一可执行文件。
下图展示了程序所传入参 argc 和 argv 的数据结构。该图使用 C 语言符号“\0”来表示每个字符串末尾的终止空字节
下面程序回显了其命令行参数,逐一按行输出,前面还冠以要显示的 argv成员名称
// 回显命令行参数
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int j;
for (j = 0; j < argc; j++)
printf("argv[%d] = %s\n", j, argv[j]);
exit(EXIT_SUCCESS);
}
因为 argv 列表以 NULL 值终止,所以可以将上面改写如下:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char **p;
for (p = argv; *p != NULL; p++){
puts(*p);
}
exit(EXIT_SUCCESS);
}
argc/argv参数机制的局限之一在于这些变量仅对main()参数可用。在保证可移植性的同时,为使这些命令行参数能为其他函数所用,必须把argv以参数形式传递给这些函数,或者是设置一个指向argv的全局变量。
要想从程序内的任意位置访问这些信息的部分或者全部内容,还有两个方法,但是会破坏程序的可移植性
- 通过linux系统专有的/proc/PID/cmdline文件可以读取任一进程的命令行参数,每个参数都以空(null)字节终止。(程序可以通过/proc/self/cmdline 文件访问自己的命令行参数。)
-
GNU C 语言库提供有两个全局变量,可在程序内任一位置使用以获取调用该程序时的程序名称(即命令行的第一个参数)
- 第一个全局变量 program_invocation_ name,提供了用于调用该程序的完整路径名。
- 第二个全局变量 program_invocation_ short_name,提供了不含目录的程序名称,即路径名的基本名称(basename)部分,定义_GNU_SOURCE宏后即可从< errno.h>中获得对这两个全局变量的声明
如下图所示,argv 和 environ 数组,以及这些参数最初指向的字符串,都驻留在进程栈上的一个单一、连续的内存区域。此区域可存储的字节数有上限要求:
-
SUSv3 规定使用 ARG_MAX 常量(定义于
< limits.h>)或者调用sysconf(_SC_ARG_MAX)函数以确定该上限值 - SUSv3 还要求 ARG_MAX 常量的下限为_POSIX_ARG_MAX(4096)个字节,而大多数 UNIX 实现的限制都远高于此。
-
但 SUSv3 并未规定对 ARG_MAX 限制的实现中是否要将一些开销字节计算在内(比如终止空字符、字节对齐、argv 和 environ 指针数组)。
Linux 中的 ARG_MAX 参数值曾一度固定为 32 个页面(在 Linux/x86-32 中即为 131072个字节),且包含了开销字节。自内核 2.6.23 版本开始,可以通过资源限制 RLIMIT_STACK来控制 argv 和 environ 参数所使用的空间总量上限,在这种情况下,允许 argv 和 environ 参
数使用的空间上限要比以前大出许多,具体限额为资源软限制 RLIMIT_ STACK 的四分之一,RLIMIT_STACK 在调用 execve()时已经生效。更多详细信息请参照 execve(2)手册页
许多程序(包括本书中的几个例子)使用 getopt()库函数解析命令行选项(即以“-”符号开头的参数)
解析
短参数之 getopt()
getopt可以解析短参数,所谓短参数就是指选项前只有一个“-”(如-t)
#include<unistd.h>
/*
* param:
* argc:通常为main函数中的argc
* argv:通常为main函数中的argv
* optstring: 短参数列表(如:"ab:c"),它由多个部分组成,表示的意义分别为:
* * 不带值的参数,它的定义即是参数本身,表示选项。
* * 必须带值的参数,它的定义是在参数本身后面再加一个冒号。
* * 单个字符后跟两个冒号,表示该选项后可以跟一个参数,也可以不跟。如果跟一个参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。
*/
int getopt (int argc, char *const *argv, const char *shortopts)
使用:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
int opt=0;
int a=0;
int b=0;
char s[50];
while((opt=getopt(argc,argv,"ab:"))!=-1)
{
switch(opt)
{
case 'a':a=1;break;
case 'b':b=1;strcpy(s,optarg);break;
}
}
if(a)
printf("option a\n");
if(b)
printf("option b:%s\n",s);
return 0;
}
string dbaddr ;
int active ;
while ((ch = getopt(argc, argv, "gi:")) > 0) {
switch (ch) {
case 'a':
dbaddr = argv[optind];
break;
case 'i':
active = atoi(optarg);
break;
default:
usage(argv[0]);
return 0;
}
}