programing

파일로 리디렉션될 때 stdout에 명시적 플러시가 필요한 이유는 무엇입니까?

batch 2023. 7. 30. 17:30
반응형

파일로 리디렉션될 때 stdout에 명시적 플러시가 필요한 이유는 무엇입니까?

printf()의 위치에 따라 달라지는 것 같습니다.stdout.

  1. 한다면stdout콘솔로 전송됩니다.printf()줄 바꿈으로 표시되며 새 줄이 인쇄된 후 플러시됩니다.
  2. 한다면stdout, 는 ""가 아닌 한 않습니다.fflush()이 호출됩니다.
  3. 만약 게가면, 약에만.printf() 앞에 됩니다.stdout는 파일로 리디렉션되고, 후속 쓰기(파일에 대한)는 줄 바꿈 처리되며, 줄 바꿈 후 플러시됩니다.

는 언제입니까?stdout줄 바꿈 및 , 그고언제리buff▁line언▁does제 그리고-.fflush()호출해야 합니까?

각 항목의 최소 예:

void RedirectStdout2File(const char* log_path) {
    int fd = open(log_path, O_RDWR|O_APPEND|O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO);
    dup2(fd,STDOUT_FILENO);
    if (fd != STDOUT_FILENO) close(fd);
}

int main_1(int argc, char* argv[]) {
    /* Case 1: stdout is line-buffered when run from console */
    printf("No redirect; printed immediately\n");
    sleep(10);
}

int main_2a(int argc, char* argv[]) {
    /* Case 2a: stdout is not line-buffered when redirected to file */
    RedirectStdout2File(argv[0]);
    printf("Will not go to file!\n");
    RedirectStdout2File("/dev/null");
}
int main_2b(int argc, char* argv[]) {
    /* Case 2b: flushing stdout does send output to file */
    RedirectStdout2File(argv[0]);
    printf("Will go to file if flushed\n");
    fflush(stdout);
    RedirectStdout2File("/dev/null");
}

int main_3(int argc, char* argv[]) {
    /* Case 3: printf before redirect; printf is line-buffered after */
    printf("Before redirect\n");
    RedirectStdout2File(argv[0]);
    printf("Does go to file!\n");
    RedirectStdout2File("/dev/null");
}

을 위한 stdout버퍼링 동작에 따라 결정됩니다.은 세 모드로 할 수 ._IOFBF: waits to (으)까지: (으)ㄹ 때까지 기다립니다.fflush() 가한능경우),우경▁if능),_IOLBF buffering: 플러시를 ), (라인 버퍼링: (라인 버퍼링: (라인 버퍼링 및_IONBF(항상 직접 쓰기가 사용됨)."되며, " 러한특성대지한이며정구되, ▁the"를 통해 영향을 수 setbuf()그리고.setvbuf() [3] 함수. " [C99:7.19.3.3]

"프로그램 시작 시 세 개의 텍스트 스트림이 사전 정의되며 명시적으로 열 필요가 없습니다. 표준 입력(기존 입력 읽기), 표준 출력(기존 출력 쓰기) 및 표준 오류(진단 출력 쓰기).처음에 열었을 때 표준 오류 스트림은 완전히 버퍼링되지 않습니다. 스트림이 대화형 장치를 참조하지 않는다고 결정될 수 있는 경우에만 표준 입력 및 표준 출력 스트림이 완전히 버퍼링됩니다." [C99:7.19.3.7]

관찰된 행동에 대한 설명

로 결정하는 입니다.stdout 테스트될 때 됩니다.대부분의 libc 구현에서 이 테스트는 스트림이 처음 사용될 때 수행됩니다.

  1. 할 수 있습니다: 때 동 #1은 게 설 명 할 수 있 습 : 니 대 장 일 용 버 되 링 고 퍼 때 인 라 치 형 화 이 스 다 작 쉽 트 림 ▁behaviour , 되 고 ▁is 링 ▁when : ▁is 1 버 퍼 ▁explainedprintf()자동으로 플러시됩니다.
  2. #때이 완전히 도#2제예이를 . 파일로 리디렉션할 때 스트림이 완전히 버퍼링되어 다음을 제외하고는 플러시되지 않습니다.fflush()엄청난 양의 데이터를 기록하지 않는 한.
  3. 마지막으로, 기본 fd에 대한 검사를 한 번만 수행하는 구현의 경우 #3도 이해합니다.를 첫 우리가처 stdout 버퍼강에서 입니다.printf()stdout이 라인 분할 모드를 획득했습니다.fd를 파일로 전환할 때 여전히 라인 버퍼링 상태이므로 데이터가 자동으로 플러시됩니다.

일부 실제 구현

각 libc는 C99가 "대화형 장치"가 무엇인지 명시하지 않고 POSIX의 stdio 엔트리가 (읽기 위해 stderr을 열 필요가 있는 것을 넘어) 이를 확장하지 않기 때문에 이러한 요구 사항을 해석하는 방법에 대한 관용도를 가집니다.

  1. Glibc. fileoalloc.c:L111 참조.사용하는 방법stat()fd가 tatty인지 테스트하고 그에 따라 버퍼링 모드를 설정합니다. (이것은 fileops.c.에서 호출됩니다.)stdout처음에는 null 버퍼가 있으며 fd 1의 특성에 따라 스트림을 처음 사용할 때 할당됩니다.

  2. BSD libc.매우 비슷하지만 따라야 할 훨씬 깨끗한 코드!makebuf.c에서 이 행을 참조하십시오.

버퍼링된 IO 기능과 버퍼링되지 않은 IO 기능을 잘못 결합하고 있습니다.이러한 조합은 특히 코드가 휴대 가능해야 할 때 매우 신중하게 수행되어야 합니다.(그리고 휴대할 수 없는 코드를 쓰는 것은 좋지 않습니다...)
동일한 파일 설명자에서 버퍼링된 IO와 버퍼링되지 않은 IO를 함께 사용하지 않는 것이 가장 좋습니다.

IO 기본 IO: fprintf(),fopen(),fclose(),freopen()...

않은 IO 퍼링되않 IO: write(),open(),close(),dup()...

를 할 때dup2()stdout을 .이 함수는 다음으로 채워진 버퍼를 인식하지 못합니다.fprintf()그래서 언제dup2()이전 설명자 1을 닫으면 버퍼가 플러시되지 않으며 내용이 다른 출력으로 플러시될 수 있습니다.당신의 경우 2a는 다음으로 전송되었습니다./dev/null.

해결책

당신의 경우에는 사용하는 것이 가장 좋습니다.freopen()dup2()이렇게 하면 모든 문제가 해결됩니다.

  1. 의 .FILE例울사례 2a)
  2. 새로 연 파일에 따라 버퍼링 모드를 설정합니다.(사례 3)

다음은 올바른 기능 구현입니다.

void RedirectStdout2File(const char* log_path) {
    if(freopen(log_path, "a+", stdout) == NULL) err(EXIT_FAILURE, NULL);
}

안타깝게도 버퍼링된 IO에서는 새로 생성된 파일의 권한을 직접 설정할 수 없습니다.권한을 변경하려면 다른 호출을 사용해야 합니다. 그렇지 않으면 이식할 수 없는 glibc 내선 번호를 사용할 수 있습니다.를 참조하십시오.

설명자를 안 설명자를 제거합니다.close(fd)그리고 가까운 stdout_bak_fd메시지가 파일에서만 인쇄되도록 하려면 이 옵션을 선택합니다.

언급URL : https://stackoverflow.com/questions/13932932/why-does-stdout-need-explicit-flushing-when-redirected-to-file

반응형