Ubuntu 中的 execl() 参数
execl() arguments in Ubuntu
我正在学习Linux编程,遇到了exec函数,它非常有用。但问题是exec函数参数非常混乱,我无法掌握哪个参数是为了什么目的。在下面的代码中execl()
函数是从通过fork()
创建的子节点调用的,execl()
中最后一个参数(NULL
)的目的是什么?
execl("/bin/ls","ls","-l",NULL);
如果有人能解释NULL
论证和其他论点的目的是什么,以及exec()
家庭功能的论点的目的是什么,那对我有很大的帮助!
创建未定义的行为。 这不是对execl
的法律呼吁。 一个 正确的调用可能是:
execl( "/bin/ls", "ls", "-l", (char*)0 );
最后一个参数必须(char*)0
,否则您有未定义的行为。 第一个参数是可执行文件的路径。 以下 参数出现在已执行程序的argv
。 这些列表 参数由(char*)0
终止;这就是被调用函数的方式 知道最后一个参数已经达成。 在上面的例子中, 例如,"/bin/ls"
的可执行文件将替换您的代码;在 它的main
,它将有argc
等于2,argv[0]
等于"ls"
, 和argv[1]
相等的"-l"
.
在此功能之后,您应该立即进行错误处理 法典。 (execl
返回时总是返回 -1,所以你不需要 测试它。 并且它仅在出现某种错误时才返回。
exec
函数是可变的:它们采用可变数量的参数,以便您可以将可变数量的参数传递给命令。函数需要使用NULL
作为标记来标记参数列表的末尾。
在可变参数函数中是一个循环,它将迭代可变数量的参数。这些环路需要一个终止条件。在某些情况下,例如printf
,实际的参数数可以从另一个参数推断出来。在其他函数中,NULL
用于标记列表的末尾。
另一种选择是为参数数量添加一个额外的函数参数,但这会使代码更加脆弱,需要程序员管理一个额外的参数,而不是简单地使用NULL
作为最终参数。
您还将看到(char *) 0
用作标记:
execl("/bin/ls", "ls", "-l", (char *) 0);
在/usr/include/libio.h
中,由于 gcc 2.8(很久以前)NULL
被定义为null(保留用于内置),在此之前NULL
被(void *)0
在varargs
情况下与(char *)0
无法区分,因为类型没有传递,例外情况是如果定义了__cplusplus
,在这种情况下NULL
定义为 0。
特别是如果你有一个 64 位架构,安全的做法是显式使用(void *)0
它被定义为与任何指针兼容,而不依赖于标准库中可能碰巧的任何狡猾#defines
。
结束参数(char *) 0
的目的是终止参数。如果缺少此功能,可能会导致未定义的行为。 手册页将execl签名定义为:
int execl(const char *path, const char *arg, ...);
path:要调用的程序的位置,要调用的程序。
arg, ...*: 可以认为是 arg0, arg1, ..., argn。
在您的情况下execl( "/bin/ls", "ls", "-l", (char*)0 );
是正确的函数调用。
">bin/ls"要调用的程序
">ls"程序名称
">-l"是该程序的参数,称为
POSIXexecl
函数的 glibc-2.34 实现如下所示。
/* Copyright (C) 1991-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/param.h>
#include <stddef.h>
/* Execute PATH with all arguments after PATH until
a NULL pointer and environment from `environ'. */
int
execl (const char *path, const char *arg, ...)
{
ptrdiff_t argc;
va_list ap;
va_start (ap, arg);
for (argc = 1; va_arg (ap, const char *); argc++)
{
if (argc == INT_MAX)
{
va_end (ap);
errno = E2BIG;
return -1;
}
}
va_end (ap);
/* Avoid dynamic memory allocation due two main issues:
1. The function should be async-signal-safe and a running on a signal
handler with a fail outcome might lead to malloc bad state.
2. It might be used in a vfork/clone(VFORK) scenario where using
malloc also might lead to internal bad state. */
ptrdiff_t i;
char *argv[argc + 1];
va_start (ap, arg);
argv[0] = (char *) arg;
for (i = 1; i <= argc; i++)
argv[i] = va_arg (ap, char *);
va_end (ap);
return __execve (path, argv, __environ);
}
libc_hidden_def (execl)
第一个循环计算argc
,即要execl
的参数数(包括第一个参数,path
)。第一个循环的条件是va_arg (ap, const char *)
。如果使用0
作为最后一个参数,则宏将扩展为如下所示的内容:
const char* temp = 0;
...
return temp;
以这种方式分配的任何标量零值都是假的。因此,使用0
作为最后一个参数将终止循环。
第二个循环形成argc
长度的参数数组,argv
。请注意,每个参数都显式转换为赋值时char*
。在0
作为最后一个参数的情况下,宏扩展argv
的结果值将与您编写的一样:
char* p = 0;
argv[i] = p;
...
同样,这绝对是一个零值,并且在 execve 的循环条件中将计算为 false。不受欢迎的意见,但使用0
作为execl
中的最后一个论点在技术上是正确的。您不必强调"它是实现并且可能不会用零填充"转换 b.s.int (32-bit) -> char* (64-bit)
,因为va_arg是一个宏 - 它当场定义了一个char*
并分配0
给它,这保证了它将具有错误的逻辑值。
"NULL"表示命令的终止。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- execl() 的参数传递到哪里
- Ubuntu 中的 execl() 参数
- execl() 返回“无法打开或解析参数”错误