【发布时间】:2019-01-15 22:33:53
【问题描述】:
我正在编写一个代码来计算父进程为init 的进程数。调用 fork 并让子级使用 exec 函数并将其输出通过管道传递回父级。在那方面一切似乎都很好,但是当我在管道的父级读取端使用fdopen,然后使用fscanf 时,程序崩溃了,即使FILE 流不是NULL。我对每个函数调用进行了检查。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
static void fatalError(char *message);
int main(int argc, char *argv[])
{
int total, initCount = 0;
int pipeToParent[2];
pid_t pid;
FILE *file;
if (pipe(pipeToParent) < 0)
fatalError("pipe() error");
if ((pid = fork()) < 0)
fatalError("fork() error");
else if (pid == 0) {
if (close(pipeToParent[0]) < 0)
fatalError("close() error");
if (dup2(pipeToParent[1], STDOUT_FILENO) < 0)
fatalError("dup2() error");
execlp("ps", "ps", "ahxo", "ppid", NULL);
fatalError("exec() error");
}
if (close(pipeToParent[1]) < 0)
fatalError("close() error");
wait(NULL);
if ((file = fdopen(pipeToParent[0], "r")) == NULL)
fatalError("fdopen() error");
for (total = 0; fscanf(file, "%d", &pid) != EOF; total++)
if (pid == 1)
initCount++;
if (fclose(file) < 0)
fatalError("fclose() error");
printf("%.2f%%\n", (float) initCount * 100 / total);
exit(EXIT_SUCCESS);
}
static void fatalError(char *message) {
perror(message);
exit(EXIT_FAILURE);
}
运行 GDB 给出了这个:
Program received signal SIGSEGV, Segmentation fault.
__isoc99_fscanf (stream=0x55757260, format=0x555555554c44 "%d") at isoc99_fscanf.c:30
30 isoc99_fscanf.c: No such file or directory.
还有 Makefile 警告:
gcc -std=c11 -g -Wall -pedantic init.c -o init
init.c: In function ‘main’:
init.c:55:14: warning: implicit declaration of function ‘fdopen’; did you mean ‘fopen’? [-Wimplicit-function-declaration]
if ((file = fdopen(pipeToParent[0], "r")) == NULL)
^~~~~~
fopen
init.c:55:12: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
if ((file = fdopen(pipeToParent[0], "r")) == NULL)
^
【问题讨论】:
-
isoc99_fscanf.c 在第 30 行有一些宏,但不知道是不是那个版本。而且它似乎不会失败。为什么 glibc 中包含调试信息?你在运行什么操作系统?你有什么 glibc 版本?顺便提一句。
fscanf(file, "%d", &pid)成功返回 1,你应该忽略它返回 0 的情况。 -
我确实收到了一个警告,询问我是否指的是
fopen而不是fdopen,不确定这是否有帮助,但我当然不是指前者 -
您是否收到警告说该函数是隐式声明的?
warning: implicit declaration of function ... -
OT:如果
exec*()函数在fork()之后失败,您几乎肯定不想在之后调用exit()- 这会将所有从父地址空间复制的缓冲数据刷新到将孩子的地址空间放入父母的文件中。它还将调用父进程注册的所有退出处理程序。_exit()存在是有原因的。 -
OT:关于:
int main(int argc, char *argv[])当main()的参数不打算使用时,使用签名:int main( void )
标签: c segmentation-fault