如何在 C 中使用 exec 传递参数并使用它们?
How to pass parameters and use them using exec in C?
我想从我的每个子进程开始一个新进程,并让它们添加通过 exec()
作为参数传递的数字。像这样的东西。我只是不知道如何访问新进程中的参数。
code.c
#include <stdio.h>
#include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <time.h>
# include <stdlib.h>
# include <dirent.h>
# include <stdio.h>
# include <string.h>
# include <getopt.h>
# include<stdbool.h>
# include <ctype.h>
# include<sys/wait.h>
# include<signal.h>
# include <sys/mman.h>
# include<sys/time.h>
void forking()
{ int a=4,b=5
for (int i=0;i<4;i++)
pid_t pID = fork();
if (pID == 0)
{
static char *argv[]={a,b,NULL};
execv("/EXEC.c",argv);
}
else
wait(pID);
}
void main(int argc, char **argv)
{
forking();
}
EXEC.c
#include <stdio.h>
#include <stdlib.h>
# include <stdio.h>
# include <string.h>
int main()
{
//Code to add a and b and print the sum
printf("%d",a+b);
}
显示的代码中存在很多很多问题:
- 无法编译。
你不应该在根目录中写 /EXEC.c
。
- 不要写在根目录。
- 不要 运行 作为 root。
- 只有 root 应该能够在根目录中写入。
- 运行 因为 root 是有风险的,应该避免。
- 不要使用看起来像源代码的名称来调用您的可执行程序 —
EXEC.c
通常是 C 源文件,而不是可以执行的程序;您需要从 EXEC.c
. 创建和 运行 EXEC
- 有些人会添加 "don't shout" — 大多数情况下,程序名称都是 lower-case,或者大部分是 lower-case;如图所示,它们很少 upper-case。
- 在这种情况下,编译
exec.c
以创建 exec
会工作 很糟糕 好吧 因为 即使 exec
是 built-in shell 命令,不在磁盘上搜索。 使用 /path/to/exec
(甚至 ./exec
)会起作用,但某些路径(至少一个 /
)是必需的。 因为您使用 execv()
,内核(不是shell)会直接执行程序。但是,您仍应使用不同的名称 — 可能会造成混淆。
- 也不要使用
test
作为您的程序的名称 — 那是另一个 shell built-in,调用您自己的程序 test
会很快或稍后,通常会更快。
- 请参阅 What should
main()
return in C and C++ — 您应该使用 int main(void)
或 int main(int argc, char **argv)
(有趣的是,您应该在 code.c
中使用较短的变体而在 [=14 中使用较长的变体=],但你把它们倒过来了)。
- 您通过
argc
和 argv
访问传递给程序的参数——参数是字符串。
- 您将参数作为字符串传递给执行的程序,而不是像您尝试使用
static char *argv[]={a,b,NULL};
那样传递给执行的程序的参数(其中 a
和 b
的类型为 int
).如果不是由此产生的错误,您应该会收到编译器警告。
- 您应该将程序名称作为
argv[0]
传递,并将操作参数作为 argv[1]
和 argv[2]
传递——您将 NULL
添加到末尾是正确的参数列表。
- 您不应该在
code.c
中包括所有您能想到的 headers — 您应该只包括您使用的那些。
- 你不应该重复
<stdio.h>
或 <stdlib.h>
。
- 你的间距应该保持一致——最好遵循第一个
#include <stdio.h> line
的模式(#
和 include
之间没有 space;一个 space 在 include
和 <stdio.h>
之间;通常没有尾随的白色 space,但如果认为有益的话允许评论,并且应该在白色 space 之前)。
EXEC.c
中的 printf()
应该在格式字符串的末尾有一个换行符。
forking()
中的代码无法编译,因为 for
循环的 body 是 pid_t pID = fork();
— 而且您不能将变量定义为body 没有大括号的循环。此外,pID
不会为 if
语句定义,除非它也在循环的 body 中。另外,a
和 b
的定义没有以分号结尾。
- 你应该在
execv()
之后有一个 exit()
之类的,最好也有错误信息,以防 execv()
失败。
- 对
wait()
的调用是错误的 — wait()
需要一个 int
指针参数,而不是普通的 int
。
可能还有其他问题需要解决。下面修改后的代码是两个文件,parent.c
和child.c
。该代码假定 child
程序在当前目录中(因此 ./child
将执行它)。你运行parent
;它创建了 child 个进程。
parent.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
static void forking(void)
{
for (int i = 0; i < 4; i++)
{
pid_t pID = fork();
if (pID == 0)
{
static char *args[] = { "./child", "4", "5", NULL };
execv(args[0], args);
fprintf(stderr, "Failed to execute %s\n", args[0]);
exit(EXIT_FAILURE);
}
else if (pID < 0)
{
fprintf(stderr, "Failed to fork()\n");
exit(EXIT_FAILURE);
}
else
{
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
printf("Process %d exited with status 0x%.4X\n", corpse, status);
if (corpse == pID)
break;
}
}
}
}
int main(void)
{
forking();
return 0;
}
child.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc != 3)
{
fprintf(stderr, "Usage: %s number1 number2\n", argv[0]);
exit(EXIT_FAILURE);
}
long number1 = strtol(argv[1], 0, 0);
long number2 = strtol(argv[2], 0, 0);
printf("%ld\n", number1 + number2);
return 0;
}
严格来说,代码应该检查 strtol()
是否有效,但正确地执行此操作很繁琐 - 请参阅 Correct usage of strtol()
? 了解更多详细信息。
示例输出
$ ./parent
9
Process 14201 exited with status 0x0000
9
Process 14202 exited with status 0x0000
9
Process 14203 exited with status 0x0000
9
Process 14204 exited with status 0x0000
$
我想从我的每个子进程开始一个新进程,并让它们添加通过 exec()
作为参数传递的数字。像这样的东西。我只是不知道如何访问新进程中的参数。
code.c
#include <stdio.h>
#include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <time.h>
# include <stdlib.h>
# include <dirent.h>
# include <stdio.h>
# include <string.h>
# include <getopt.h>
# include<stdbool.h>
# include <ctype.h>
# include<sys/wait.h>
# include<signal.h>
# include <sys/mman.h>
# include<sys/time.h>
void forking()
{ int a=4,b=5
for (int i=0;i<4;i++)
pid_t pID = fork();
if (pID == 0)
{
static char *argv[]={a,b,NULL};
execv("/EXEC.c",argv);
}
else
wait(pID);
}
void main(int argc, char **argv)
{
forking();
}
EXEC.c
#include <stdio.h>
#include <stdlib.h>
# include <stdio.h>
# include <string.h>
int main()
{
//Code to add a and b and print the sum
printf("%d",a+b);
}
显示的代码中存在很多很多问题:
- 无法编译。
你不应该在根目录中写
/EXEC.c
。- 不要写在根目录。
- 不要 运行 作为 root。
- 只有 root 应该能够在根目录中写入。
- 运行 因为 root 是有风险的,应该避免。
- 不要使用看起来像源代码的名称来调用您的可执行程序 —
EXEC.c
通常是 C 源文件,而不是可以执行的程序;您需要从EXEC.c
. 创建和 运行 - 有些人会添加 "don't shout" — 大多数情况下,程序名称都是 lower-case,或者大部分是 lower-case;如图所示,它们很少 upper-case。
- 在这种情况下,编译
exec.c
以创建exec
会工作很糟糕好吧因为即使exec
是 built-in shell 命令,不在磁盘上搜索。使用因为您使用/path/to/exec
(甚至./exec
)会起作用,但某些路径(至少一个/
)是必需的。execv()
,内核(不是shell)会直接执行程序。但是,您仍应使用不同的名称 — 可能会造成混淆。 - 也不要使用
test
作为您的程序的名称 — 那是另一个 shell built-in,调用您自己的程序test
会很快或稍后,通常会更快。 - 请参阅 What should
main()
return in C and C++ — 您应该使用int main(void)
或int main(int argc, char **argv)
(有趣的是,您应该在code.c
中使用较短的变体而在 [=14 中使用较长的变体=],但你把它们倒过来了)。 - 您通过
argc
和argv
访问传递给程序的参数——参数是字符串。 - 您将参数作为字符串传递给执行的程序,而不是像您尝试使用
static char *argv[]={a,b,NULL};
那样传递给执行的程序的参数(其中a
和b
的类型为int
).如果不是由此产生的错误,您应该会收到编译器警告。 - 您应该将程序名称作为
argv[0]
传递,并将操作参数作为argv[1]
和argv[2]
传递——您将NULL
添加到末尾是正确的参数列表。 - 您不应该在
code.c
中包括所有您能想到的 headers — 您应该只包括您使用的那些。 - 你不应该重复
<stdio.h>
或<stdlib.h>
。 - 你的间距应该保持一致——最好遵循第一个
#include <stdio.h> line
的模式(#
和include
之间没有 space;一个 space 在include
和<stdio.h>
之间;通常没有尾随的白色 space,但如果认为有益的话允许评论,并且应该在白色 space 之前)。 EXEC.c
中的printf()
应该在格式字符串的末尾有一个换行符。forking()
中的代码无法编译,因为for
循环的 body 是pid_t pID = fork();
— 而且您不能将变量定义为body 没有大括号的循环。此外,pID
不会为if
语句定义,除非它也在循环的 body 中。另外,a
和b
的定义没有以分号结尾。- 你应该在
execv()
之后有一个exit()
之类的,最好也有错误信息,以防execv()
失败。 - 对
wait()
的调用是错误的 —wait()
需要一个int
指针参数,而不是普通的int
。
EXEC
可能还有其他问题需要解决。下面修改后的代码是两个文件,parent.c
和child.c
。该代码假定 child
程序在当前目录中(因此 ./child
将执行它)。你运行parent
;它创建了 child 个进程。
parent.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
static void forking(void)
{
for (int i = 0; i < 4; i++)
{
pid_t pID = fork();
if (pID == 0)
{
static char *args[] = { "./child", "4", "5", NULL };
execv(args[0], args);
fprintf(stderr, "Failed to execute %s\n", args[0]);
exit(EXIT_FAILURE);
}
else if (pID < 0)
{
fprintf(stderr, "Failed to fork()\n");
exit(EXIT_FAILURE);
}
else
{
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
printf("Process %d exited with status 0x%.4X\n", corpse, status);
if (corpse == pID)
break;
}
}
}
}
int main(void)
{
forking();
return 0;
}
child.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc != 3)
{
fprintf(stderr, "Usage: %s number1 number2\n", argv[0]);
exit(EXIT_FAILURE);
}
long number1 = strtol(argv[1], 0, 0);
long number2 = strtol(argv[2], 0, 0);
printf("%ld\n", number1 + number2);
return 0;
}
严格来说,代码应该检查 strtol()
是否有效,但正确地执行此操作很繁琐 - 请参阅 Correct usage of strtol()
? 了解更多详细信息。
示例输出
$ ./parent
9
Process 14201 exited with status 0x0000
9
Process 14202 exited with status 0x0000
9
Process 14203 exited with status 0x0000
9
Process 14204 exited with status 0x0000
$