对 execvp 系统调用的调用如何工作?
How do calls to the execvp system call work?
我正在研究另一个 Whosebug question 的内容,我认为现在是温习 unix 系统调用知识的好时机。
在尝试 execvp
时(WITHOUT 故意分叉)我 运行 遇到了让我感到困惑的事情
我写了4个测试程序
计划 1
#include <stdio.h>
int main() {
//printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
程序按预期运行,打印了目录的内容,Foo
打印语句没有
计划 2
然而,当我取消注释第一个打印语句并让程序成为这样时
#include <stdio.h>
int main() {
printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
execvp
returns a -1
并且发出了两个打印语句。为什么?
计划 3
我依稀记得在大学里试验 unix 系统调用时不得不使用 unistd.h
。
所以我包含了它,但 execvp
没有不同的签名,它需要更多的参数,而不仅仅是程序的名称。所以我这样做了
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
这行得通。这让我很困惑。为什么 exec 在第一个程序中工作?
我还使用 This 作为系统调用的参考。
终于写好了
节目 4
#include <stdio.h>
//#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
这也符合预期。
谁能解释一下这是怎么回事?
有了这个片段
#include <stdio.h>
int main() {
execvp("ls");
printf("Foo\n");
return 0;
}
您正在调用未定义的行为。您没有提供 execvp
的原型,它需要一个参数列表(以 null 终止)作为第二个参数。
在没有任何警告选项的情况下使用 gcc
会静默使用 execvp
作为隐式声明,并且不检查参数。它只是调用函数。然后该函数查找第二个参数并遇到...调用堆栈(或寄存器,取决于调用约定)剩下的任何内容,这就是为什么先前的 printf
调用可以改变行为的原因。
使用 gcc -Wall
给出以下警告:
test.c:5:9: warning: implicit declaration of function 'execvp' [-Wimplicit-function-declaration]
execvp("ls");
包括正确的包含 (#include <unistd.h>
) 导致:
test.c:6:9: error: too few arguments to function 'execvp'
execvp("ls");
^~~~~~
这就是为什么你有奇怪的行为。别再看了。将 execvp
与 2 个参数、句点一起使用。在你的情况下 "Program 3" 是要走的路,并且尽可能将警告级别设置为最大(gcc
和 clang
:-Wall -Wextra -pedantic -Werror
)
我正在研究另一个 Whosebug question 的内容,我认为现在是温习 unix 系统调用知识的好时机。
在尝试 execvp
时(WITHOUT 故意分叉)我 运行 遇到了让我感到困惑的事情
我写了4个测试程序
计划 1
#include <stdio.h>
int main() {
//printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
程序按预期运行,打印了目录的内容,Foo
打印语句没有
计划 2
然而,当我取消注释第一个打印语句并让程序成为这样时
#include <stdio.h>
int main() {
printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
execvp
returns a -1
并且发出了两个打印语句。为什么?
计划 3
我依稀记得在大学里试验 unix 系统调用时不得不使用 unistd.h
。
所以我包含了它,但 execvp
没有不同的签名,它需要更多的参数,而不仅仅是程序的名称。所以我这样做了
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
这行得通。这让我很困惑。为什么 exec 在第一个程序中工作? 我还使用 This 作为系统调用的参考。
终于写好了
节目 4
#include <stdio.h>
//#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
这也符合预期。
谁能解释一下这是怎么回事?
有了这个片段
#include <stdio.h>
int main() {
execvp("ls");
printf("Foo\n");
return 0;
}
您正在调用未定义的行为。您没有提供 execvp
的原型,它需要一个参数列表(以 null 终止)作为第二个参数。
在没有任何警告选项的情况下使用 gcc
会静默使用 execvp
作为隐式声明,并且不检查参数。它只是调用函数。然后该函数查找第二个参数并遇到...调用堆栈(或寄存器,取决于调用约定)剩下的任何内容,这就是为什么先前的 printf
调用可以改变行为的原因。
使用 gcc -Wall
给出以下警告:
test.c:5:9: warning: implicit declaration of function 'execvp' [-Wimplicit-function-declaration]
execvp("ls");
包括正确的包含 (#include <unistd.h>
) 导致:
test.c:6:9: error: too few arguments to function 'execvp'
execvp("ls");
^~~~~~
这就是为什么你有奇怪的行为。别再看了。将 execvp
与 2 个参数、句点一起使用。在你的情况下 "Program 3" 是要走的路,并且尽可能将警告级别设置为最大(gcc
和 clang
:-Wall -Wextra -pedantic -Werror
)