进程环境
main()函数
每一个完整的C程序都必须有一个名为main()的函数,系统通过调用main()开始执行一个C程序。在ANSI C中,main()可以没有参数,也可以定义它取两个参数。两个参数的main()原型定义为:
int main(int argc, char **argv);
main()的两个参数给出该程序运行时的命令行参数,其中argc给出命令行参数个数,argv是指向命令行参数字符串的指针数组。
尽管我们说C程序是从main()开始执行的,但实际上程序的真正启动点是系统提供的一个初启函数,该函数位于名为crt0.o的文件中。当编译C程序时,链接器ld会将此文件与C程序文件装配在一起形成可执行文件,并指定该初启函数为程序的开始执行地址。这个初启函数负责从UNIX shell获得命令行参数和环境变量之值,并将它们组织成main()函数需要的参数形式,然后调用main()函数。此外,当C程序从main()返回时,初启函数也负责调用exit()终止进程。
命令行参数
命令行参数是在启动程序执行的shell命令中给出的以空格分开的字符串。当程序执行时,调用exec()的进程(shell或用户进程)可以将命令行参数传送给它。程序能够看到命令行参数的唯一途径是通过main(),如果main()没有参数,则得不到命令行。
main()从参数argc获得命令行参数个数,从argv获得参数值。argv是一个字符指针组成的数组,它的每一个元素指向命令行中参数对应的字符串。例如,对于命令
$./a.out -f foo bar
main()的argc为4且argv有4个元素,它们依次为:“a.out”、“-f”、“foo”和“bar”。
如果程序的命令行参数很简单,则可直接从argv中获取这些参数,如下所示:
main(int argc, char **argv) {
int i;
for (i = 0; i < argc; i++)
printf("argv[%d]: %s\n", i, argv[i]);
}
当程序的执行允许在命令行中给出较多和较复杂的参数时,这些参数最好遵循POSIX推荐的语法并用函数getopt()来读取它们。
命令行参数的语法约定
POSIX对UNIX中实用程序的命令行参数有下述推荐语法约定,遵循这些约定的命令行参数可以使用getopt()来分解和接收。
实用程序命令行由实用程序名后随选项、选项值以及操作数组成。
实用程序名应该包含至少两个、至多9个字符,且只包含小写字母和数字。
如果参数以短横线分隔符’-'开头,则这个参数是选项。
选项名必须是单个字母或数字字符,-W选项保留给实现扩展使用,不允许多数字选项。
选项可以要求有选项值。例如,ld命令的‘-o’选项要求一个选项值,即输出文件名。
选项和它的选项值可以作为也可以不作为分开的单词(换言之,它们中间的空白是可选的)。因此,“-o foo”和“-ofoo”等价。
如果多个选项均不要求有选项值的话,可以集中放在一个短横线分隔符之后作为一个单词,因而“-abc”等价于“-a-b-c”。
在命令行中,所有选项应先于操作数。
第一次出现的参数“–”终止所有选项。后继的任何参数均视为操作数,即使它们是以‘-’开头的单个字符也是如此。
仅由一个短横线字符组成的单词按操作数解释。UNIX系统约定,它用于指定来自标准输入流的输入或标准输出流的输出。例如,如下命令中,单个短横线‘-’是选项参数-o的值,它代表标准输出流,即指定将汇编文件输出到标准输出流。
%gcc -S file.c -o - -pipe
多个选项可按任意顺序出现,单个选项也可多次出现,其解释留给应用程序。
注意,这里命令行参数分为了“选项”和“操作数”。选项首先是以‘-’开头的单个字母或数字组成的参数,其次必须位于所有操作数之前。本书中涉及命令行参数时,术语“选项”和“操作数”将遵循这里的定义。
扫描命令行中的选项
如果程序的命令行遵循上一节的语法约定,则可用getopt()来读取其中的选项。
#include <unistd.h>
int getopt(int argc, char *const argv[], const *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
getopt()从argc和argv指定的命令行参数表中获取下一选项参数,argc和argv通常直接来自于main()接收的参数。
参数optstring是一个字符串,它给出程序允许的合法选项字符。其中,选项字符之后可以跟有冒号‘∶’,以指出其后要求有选项值。例如,字符串“if:ls”表示允许选项-i、-f、-l和-s,且-f要求跟有一个选项值。如果指定选项要求有选项值的话,命令行中必须给出选项值。
根据参数optstring的指引,getopt()每次从命令行中获取一个选项。如果存在选项,它返回选项字符。对于那些接收值的选项,它同时设置外部变量optarg指向对应的选项值。应用无须复制optarg字符串,因为它指向的是argv数组,而不是可能被覆盖的静态区。另外,确定一个选项是否需要值是程序员自己的责任,getopt()仅根据optstring的指引,当选项要求有值时,它会无条件地将其后的一个参数当作该选项的值返回在optarg中。从getopt