我正在编写一个代码,该代码将计算父进程为init
的进程数。称为fork并让孩子使用exec
函数,并通过管道将其输出传递回父对象。一切似乎都很好,但是当我在父级管道的读取端上使用fdopen
时,接着是fscanf
,即使FILE
流不是{{ 1}}。我对每个函数调用都进行了检查。
NULL
正在运行的GDB给出了这一点:
#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);
}
以及Makefile警告:
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.
答案 0 :(得分:2)
在C中,如果以前的函数声明不存在,则假定函数返回了int
。如果编译器假定函数在返回int
时返回FILE *
,并且如果sizeof(FILE*) < sizeof(int)
返回值将被截断并且无效。因此,当传递给fscanf
的指针被截断且无效时,您会遇到内部glibc错误。
在man fdopen中,您可以阅读:
fdopen(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
这些是您需要定义的宏,以便在程序中具有fdopen()
声明。您需要在任何包含之前 定义它们。我通常只定义_GNU_SOURCE
中的_POSIX_C_SOURCE
等。{p>
features.h
有关更多信息,请参见future test macros。
使用#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
.. rest of the program ...
时,您也可以执行gcc
或其他gcc -std=gnu11
。 -std=gnu*
与-std=c11
相同,除了在编译时预定义了宏-std=gnu11
。
答案 1 :(得分:2)
对于Linux man page for fdopen()
,Linux / glibc要求定义_POSIX_C_SOURCE
宏:
glibc的功能测试宏要求(请参阅 feature_test_macros(7)):
fdopen(): _POSIX_C_SOURCE
否则,您将获得一个隐式声明,如前所述,这意味着假定该函数返回int
。 fdopen()
实际上返回的指针可能不适合该int
,因此它被截断了。