【问题标题】:How do calls to the execvp system call work?对 execvp 系统调用的调用如何工作?
【发布时间】:2018-04-19 20:42:44
【问题描述】:

我正在研究另一个 StackOverflow question 的内容,我认为现在是复习我的 unix 系统调用知识的好时机。

在尝试execvp没有故意分叉)时,我遇到了一些让我困惑的事情

我写了 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 返回一个-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;
}

这也可以按预期工作。

有人可以解释发生了什么吗?

【问题讨论】:

  • execvp("ls"); 是未定义的行为:第二个参数是参数列表。你在扔垃圾。
  • 但是当我包含unistd.h 时,为什么它只以编译器错误的形式抱怨呢?此外,如果 execp 仅使用 2 个参数定义,为什么它甚至让我 execvp("ls")
  • 没有警告选项,execvp 被静默隐式声明,不检查参数列表。
  • 请原谅我的无知,但是默默地隐式声明,不检查参数列表是什么意思?如果execp 是在unistd 中定义的,我怎么能在不包含它的情况下运行它?
  • 因为编译器是允许的,所以必须始终设置最高级别的警告。

标签: c exec system-calls


【解决方案1】:

有了这个sn-p

#include <stdio.h>

int main() {
        execvp("ls");
        printf("Foo\n");
        return 0;
}

您正在调用未定义的行为。您没有提供 execvp 的原型,它需要一个参数列表(以空结尾)作为第二个参数。

在没有任何警告选项的情况下使用gcc 会默默地使用execvp 作为隐式声明,并且不检查参数。它只是调用函数。然后该函数查找第二个参数并遇到......调用堆栈(或寄存器,取决于调用约定)剩下的任何内容,这就是以前的printf 调用可以改变行为的原因。

使用gcc -Wall 会给出以下警告:

test.c:5:9: warning: implicit declaration of function 'execvp' [-Wimplicit-function-declaration]
         execvp("ls");

包含正确的包含 (#include &lt;unistd.h&gt;) 会导致:

test.c:6:9: error: too few arguments to function 'execvp'
         execvp("ls");
         ^~~~~~

这就是为什么你有奇怪的行为。不要再看下去了。使用 execvp 和 2 个参数,句号。在您的情况下,“程序 3”是要走的路,如果可能,请始终将警告级别设置为最大值(gccclang-Wall -Wextra -pedantic -Werror

【讨论】:

  • 谢谢,这解决了。我不知道 gcc 有时可以使用这样的函数的隐式声明。我认为-Wall 将成为我前进的支柱:)
  • -Wall -Wextra -pedantic -Werror 应该是默认值。但有时你会遇到“无法修改”的垃圾代码......
  • -Wall -Wextra -pedantic -Werror 听起来很棒。我刚试了一下,我真的很喜欢。感谢这个宝石:)
猜你喜欢
  • 1970-01-01
  • 2012-12-23
  • 1970-01-01
  • 2011-09-08
  • 2021-07-24
  • 2023-04-09
  • 2014-11-17
  • 2015-02-23
相关资源
最近更新 更多