当前位置:   article > 正文

main程序参数(Beginning Linux Programming)_line 56: char 5: error: redefinition of ‘main’ [so

line 56: char 5: error: redefinition of ‘main’ [solution.c] 59 | int main(

4.1 程序参数

当一个用C语言编写的Linux或UNIX程序运行时,它是从main函数开始的。对这些程序而言,main函数的声明如下所示:

int main(int argc,char*argv[])

其中argc是程序参数的个数,argv是代表参数自身的字符串数组。

你可能也会看到Linux的C程序将main函数简单的声明为:

main()

这样也行,因为默认的返回值类型是int,函数中不用的形式参数不需要声明。argc和argv仍在,但如果不声明它们,你就不能使用它们。

无论操作系统何时启动新程序,参数argc和 argv都被设置并传递给main。这些参数通常由其他程序提供,这个程序一般是shell,它请求操作系统启动该新程序。shell接受用户输入的命令行,将命令行分解成单词,然后把这些单词放入argv数组。请记住:Linux的shell一般会在设置argc和argv之前对文件名参数进行通配符扩展,而MS-DOS的shell则期望程序接受带通配符的参数并执行它们自己的通配符扩展。

例如,如果我们给shell输入如下命令:

$myprog lef right 'and center'

 

程序myprog将从main函数开始,main带的参数是:

artc:4

argv:{"myprog","left","right","and center"}

注意,参数个数包括程序名自身,argv数组也包含程序名并将它作为第一个元素argv[0]。因为我们在shell命令里使用了引号,所以第四个参数是一个包含了空格的字符串。

如果你用ISO/ANSI C语言编写过程序,就会对上面的这些很熟悉。main的参数对应shell脚本里的位置参数$0、$1等。ISO/ANSI C只规定main必须返回int,而X/Open规范则给出了如上所示的明确声明。

命令行参数在向程序传递信息方面是很有用的。例如, 我们可以在一个数据库应用程序中使用命令行参数来传递想用的数据库的名字,这样就可以在不止一个数据库上使用同一个程序。许多工具程序也使用命令行参数来 改变程序的行为或设置选项。通常,你可以使用一个以短横线(-)开头的命令行参数来设置这些所谓的标志(flag)或开关(switch)。例如,sort程序可以用一个开关来进行逆向排序(与正常排序相反):

$ sort -r file

命令行选项非常常用,因此按相同的方式使用它们对程序的使用者来说是一个不小的帮助。过去,每个工具程序采用它们各自的方式来使用命令行选项,这带来了一些混乱。例如,请看下面这些命令使用参数的方式:

$ tar cvfB /tmp/file.tar 1024

$ dd if=/dev/fd0 of=/tmp/file.dd bs=18k

$ ls -lstr

$ ls -l -s -t -r

所有命令行开关都应以一个短横线开头,并且包含单个字母或数字。不带后续参数的选项可以在一个短横线后归并到一起。这里的两个ls命令的例子就遵循了以上规则。如果一个选项需要值,则该值应作为独立的参数 紧跟在选项后。dd命令的例子违背了这一规则,因为它使用了多字符的选项,而且选项未以短横线开头(if=/dev/fd0),而tar命令则把选项和它 们的值完全分开!

还有些程序有一个怪异的地方,就是用选项+x(举例来说)执行与-x相反的功能。

撇开风格各异的语法格式不谈,单是记住所有这些程序 选项的顺序和含义就已经非常困难了。通常,只有求助于-h(帮助)选项或man手册页(如果程序员提供了的话)。我们将在本章稍后看到,getopt提供 了对这些问题的一个优雅的解决方案。不过现在,我们还是先看看传递到程序中的参数是怎样处理的。

实验:程序参数

下面这个程序args.c对其参数进行检查:

运行这个程序时,它只是打印其参数和发现的选项。我们的意图是,让该程序接受一个字符串参数和一个由-f选项引入的可选的文件名参数。其他的选项也可以被定义。

$ ./args -i -lr 'hi there' -f fred.c

argument 0:args

option: i

option: lr

argument 3: hi there

option: f

argument 5: fred.c

实验解析

这个程序简单地利用计数参数argc建立一个循环以检查所有程序参数。它通过检查首字母是否是短横线来发现选项。

在本例中,如果打算支持-l选项和-r选项,那么我们就漏考虑了一种情况:-lr选项应该和-l –r一样处理。

X/Open规范定义了命令行选项的标准用法(工具语法规则),同时定义了在C语言程序中提供命令行开关的标准编程接口:getopt函数。

4.1.1 getopt

为了帮助我们遵循这些规则,Linux提供了getopt函数,它支持需要关联值和不需要关联值的选项,而且简单易用。

#include<unistd.h>

int getopt(int argc, char *const argv[], const char *optstring);

extern char *optarg;

extern int optind, opterr, optopt;

getopt函数将传递给程序的main函数的 argc和argv作为参数,同时接受一个选项指定符字符串optstring,该字符串告诉getopt哪些选项可用,以及每个选项是否有关联值。 optstring只是一个字符列表,每个字符代表一个单字符选项。如果一个字符后面紧跟一个冒号(:),则表明该选项有一个关联值作为下一个参数。 bash中的getopts命令执行类似的功能。

例如,可以用下面的调用来处理上面的例子:

getopt(argc, argv, "if:lr");

 

它允许几个简单的选项:-i、-l、-r和-f,其中-f选项后要紧跟一个文件名参数。使用相同的参数,但以不同的顺序来调用命令将改变程序的行为。你可以在本章的下一个实验部分进行尝试。

getopt的返回值是argv数组中的下一个选项字符(如果有的话)。循环调用getopt就可以依次得到每个选项。getopt有如下行为:

l 如果选项有一个关联值,则外部变量optarg指向这个值。

l 如果选项处理完毕,getopt返回-1,特殊参数--将使getopt停止扫描选项的工作。

l 如果遇到一个无法识别的选项,getopt返回一个问号(?),并把它保存到外部变量optopt中。

l 如果一个选项要求有一个关联值(例如我们例子中的-f),但未提供这个值,则getopt将返回一个冒号(:)。

外部变量optind被设置为下一个待处理参数的索引。getopt用它来记录自己的进度。很少有程序需要对这个变量进行设置。当所有选项都处理完毕后,optind指向argv数组尾部——可以找到其余参数的地方。

有些版本的getopt会在第一个非选项参数处停下 来,返回-1并设置optind的值。而其他一些版本,如Linux提供的版本,能够处理出现在程序参数中任意位置的选项。注意,此时,getopt实际 上重写了argv数组,把所有非选项参数都集中在一起,从argv[optind]位置开始。对GNU版本的getopt而言,这一行为是由环境变量 POSIXLY_CORRECT来控制的,如果它被置位,getopt就会在第一个非选项参数处停下来。此外,还有些getopt版本会在遇到未知选项时 打印出错信息。注意:根据POSIX规范的说法,如果opterr变量是非零值,getopt就会向stderr打印一条出错信息。

实验:getopt函数

我们在这个例子中使用getopt函数,并将新程序命名为argopt.c:

现在,当我们运行这个程序时,就会发现所有命令行参数都被自动处理了。

实验解析

这个程序循环调用getopt对选项参数进行处理,直到处理完毕,此时getopt会返回-1。每个选项(包括未知选项和缺少关联值的选项)都有相应的处理动作。根据使用的getopt版本,你看到的输出可能和上面显示的略有不同,尤其是出错信息部分,但含义都是明确的。

当所有选项都处理完毕后,程序像以前一样把其余参数都打印出来,但这次是从optind位置开始。

4.1.2 getopt_long

许多Linux应用程序接受比我们在前面例子中所用的单字符选项含义更明确的参数。GNU C库包含getopt的另一个版本,称作getopt_long,它接受以双短横线(--)开始的所谓长参数。

我们可以使用getopt_long为示例程序创建一个新版本,它可以使用与前面选项等效的长参数选项,如下所示:

事实上,新的长选项和最初的单字符选项可以混合使用。只要能够区分开,长选项也可以缩写。有关联值的长选项可以按照格式--option=value作为单个参数给出,如下所示:

新程序longopt.c如下所示,其中为支持长选项而对argopt.c所做的修改以阴影显示。

实验解析

getopt_long函数比getopt多两个附 加的参数。第一个是结构数组,它描述了每个长选项并告诉getopt_long如何处理它们。第二个是变量指针,它可以作为optind的长选项版本使 用。对于每个识别的长选项,它在长选项数组中的索引就写入该变量。在此例子中,我们不需要这一信息,因此第二个附加参数是NULL。

长选项数组由一些类型为struct option的结构组成,每个结构描述了一个长选项的行为。该数组必须以一个包含全0的结构结尾。

长选项结构在getopt.h中定义,并且它必须与常量_GNU_SOURCE一同包含进来,该常量启用getopt_long功能。

该结构的成员如表4-1所示。

表 4-1

name

长选项的名字。缩写也可以接受,只要不与其他选项混淆

has_arg

该选项是否带参数。0表示不带参数,1表示必须有一个参数,2表示有可选参数

flag

设置为NULL表示当选项找到时,getopt_long返回在成员val里给出的值。否则,getopt_long返回0并将val的值写入flag指向的变量

val

getopt_long为该选项返回的值

要了解GNU对getopt扩展的其他选项及相关函数,请参考getopt的手册页。

 

类别:c的问题 | 添加到搜藏 | 浏览( 235) | 评论 (0) <script type="text/javascript"></script>
 
 

 

<script type="text/javascript"></script>

最近读者:
<script type="text/javascript"></script>
登录后,您就出现在这里。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/160786
推荐阅读
相关标签
  

闽ICP备14008679号