在《UNIX环境高级编程》一书中,讲到exec函数及其使用,其中有一个例子,简单来说就是这样:
execlp(“ls”, “ls”, “-al”, (char *)0);
其输出结果就跟我们在终端里输入ls命令得到的结果一样。
在说疑问之前,先看函数的定义:
int execlp(const char *file, const char *arg, … /* (char *) NULL */);
其中第一个参数file指向可执行文件名称,因为execlp()函数会从系统PATH路径中寻找相应命令,所以不需要带完整路径;
第二个参数之后就都是传给可执行文件的参数,类似main函数的args[],只是最后一个参数必须为空字符指针;
疑问是这样的,当我们在终端输入 ls -al 的时候,对应到execlp中应该是 file,arg[0] 或是 file,arg[1] 呢?要完全对应应该输入ls ls -al,但这又不合法,所以最有可能是file, arg[1],那此时的 arg[0] 又在哪里,谁给的?
其实这个疑问还是很好解释的,《UNIX环境高级编程》一书中有提到,当内核起动C程序时会使用一个exec函数(7.2 main函数 ),而我们也知道,shell执行命令的方式就是fork+exec,所以我们执行ls命令不带参数并非代表没有这个参数,argv[0]这个参数系统还是会传递给exec函数的,我们可以做个试验
int main(int num_args, const char* args[])
{
for(int i = 0; i < num_args; ++i)
{
printf(“args[%d] = %s\n”, i, args[i]);
}
return 0;
}
编译后执行该程序
$./a.out
args[0] = ./a.out
由此可见,我们执行./a.out,本意是指示可执行程序的路径和名称(对应execlp中的file指针),看起来不带参数,但args[0]还是存在;同理我们执行ls,不带参数,但ls还是能从系统中得到arg[0]这个参数。
至于这个参数是什么,那是另外一回事了,比如某些shell会将此参数设置为完全的路径名(8.9 exec函数)。