[英]fscanf causes segmentation fault
我正在編寫一個代碼,該代碼將計算父進程為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)
^
在C中,如果沒有以前的函數聲明,則假定該函數返回int
。 如果編譯器假定函數在返回FILE *
時返回int
,並且如果sizeof(FILE*) < sizeof(int)
則返回值將被截斷並且無效。 因此,由於傳遞給fscanf
的指針被截斷且無效,因此會出現內部glibc錯誤。
從man fdopen您可以閱讀:
fdopen(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
這些是您需要定義的宏,以便在程序中具有fdopen()
聲明。 您需要先定義它們, 然后再包含。 我通常只定義_GNU_SOURCE
,它在features.h
定義_POSIX_C_SOURCE
等。
#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
相同,除了在編譯時預定義了宏_GNU_SOURCE
之外。
對於fdopen()
的Linux手冊頁 ,Linux / glibc要求定義_POSIX_C_SOURCE
宏:
glibc的功能測試宏要求(請參閱feature_test_macros(7) ):
fdopen(): _POSIX_C_SOURCE
否則,您將獲得一個隱式聲明,如前所述,這意味着假定該函數返回int
。 fdopen()
實際上返回的指針可能不適合該int
,因此被截斷了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.