C/C++编程:命令行参数

  • Post author:
  • Post category:其他


每个 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;
        }
    }