一.main函数的参数解析
一般来说,我们写main函数,就定义main(),它的参数部分看似没有,实际上,main函数也是有参数的,只是在我们写时省略了。
main函数的参数由三部分组成,分别是argc(int型,表示命令行参数的个数)、argv[](char*数组型,指向命令行的每一个命令参数)、envp[](char*数组型,指向环境变量)。
说明:argc包括程序本身,所以它大于等于1。argv以NULL结尾,且也包括程序本身,所以它的元素个数大于等于2。
在Linux系统和Windows中,用户要想看到main函数的各个参数,实现方法有所差异。请看如下:
图一
图二
图二中的-a和-b均为命令行参数,2.c经过预处理、编译、汇编、链接生成的可执行二进制文件a.out是argv[0],即第一个参数,-a和-b作为第二个参数。
在Windows平台下输入如下程序实现加法:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
int x=atoi(argv[2]);
int y=atoi(argv[3]);
if(argc!=4)
{
return 1;
}
if(strcmp(argv[1],"-a")==0)
{
printf("%d+%d=%d\n",x,y,x+y);
}
}
输入参数在该程序的属性中输入,若输入11和22,如图:
二.可变参数列表
1.可变参数列表的出现形式和使用条件
我们有时会看到这样的程序:int average(int n,...) int n后面的“...”是什么意思呢?
这就是我今天要说的可变参数列表部分。我们都知道在函数名后面的()里放的是形参变量,形参实例化时形参由右向左依次进栈。所以n最后入栈,而可变参数列表部分就是根据已知的n依次向上,来明确这些参数。如:
设指针p指向已知的变量n,要得到a的内容,则对指针p+1,再进行解引用就能得到a的值。但是我们知道对指针加1实际上加的是指针所指向类型的大小,在这里很明显,a和n的类型不同,所以要对指针进行强制类型转换再进行解引用。同理b、c、d、e的内容也是通过这种对指针进行++,再对指针进行强制类型转换,最后通过解引用来得到的。
所以对于可变参数列表的使用,有如下前提条件:(1)使用可变参数列表,必须知道每一个参数的类型(否则无法对指针进行强转)(2)必须知道已明确变量的地址(例题中的n)(3)必须知道共传参的参数个数
2.实例分析
说明:在这里用到了几个宏:
(1)va_list表示类型,定义了一个va_list类型的变量arg.
(2)va_start:把定义的变量arg强转为和指向n类型的指针变量。它的第一个参数是arg,第二个参数是可变参数列表前的最后一个参数。
(3)va_arg:根据参数类型,提取每个参数内容。第一个参数为上面定义过的指针变量arg,第二个参数是可变参数列表中的参数类型。先对arg解引用,然后让它指向先当前变量一步进栈的变量。
(4)va_end:结束可变参数提取。 使arg指向空。
3.可变参数的限制
(1)可变参数必须从头到尾逐个访问。如果想在访问了几个可变参数后半途终止,这是可以的。但是,如果想一开始就访问可变参数列表中间的参数,是不行的。
(2)参数列表中至少有一个命名参数。否则无法使用va_start。
(3)上面的宏是无法直接判断出实际存在参数的数量。
(4)如果在va_arg中指定了错误的类型,那么其后果是无法预测的。