programing

fflush (stdin) 사용

nasanasas 2020. 11. 11. 20:14
반응형

fflush (stdin) 사용


따라서 fflush(stdin)입력 버퍼를 지우는 Google의 빠른 검색은 사용에 대해 경고하는 수많은 웹 사이트를 보여줍니다. 그러나 그것은 정확히 제 CS 교수가 수업에 그것을 가르치는 방법입니다.

사용이 얼마나 나쁜 fflush(stdin)가요? 교수님이 사용하고 있고 흠 잡을 데없이 작동하는 것처럼 보이지만 정말 사용을 자제해야합니까?


단순함 : 이는 fflush출력 스트림에서 호출 되기 때문에 정의되지 않은 동작 입니다. 이것은 C 표준에서 발췌 한 것입니다.

int fflush (파일 * ostream);

ostream은 가장 최근 작업이 입력되지 않은 출력 스트림 또는 업데이트 스트림을 가리 킵니다. fflush 함수는 해당 스트림에 대한 기록되지 않은 데이터가 호스트 환경에 전달되어 파일에 기록되도록합니다. 그렇지 않으면 동작이 정의되지 않습니다.

따라서 이것이 "얼마나 나쁜지"에 대한 질문이 아닙니다. fflush(stdin)이다 분명히 잘못 , 당신은 지금, 그것을 사용하지 않아야합니다 .


댓글을 답으로 변환하고 문제가 주기적으로 다시 나타나기 때문에 댓글을 확장합니다.

표준 C 및 POSIX fflush(stdin)는 정의되지 않은 동작으로 남겨 집니다.

에 대한 POSIX , C 및 C ++ 표준 fflush()은 동작이 정의되지 않았다고 명시 적으로 설명하지만 시스템이 정의하는 것을 방해하는 것은 없습니다.

ISO / IEC 9899 : 2011 — C11 표준 — 내용 :

§7.21.5.2 fflush 기능

¶2 stream가장 최근 작업이 입력 fflush되지 않은 출력 스트림 또는 업데이트 스트림을 가리키는 경우 함수는 해당 스트림에 대해 기록되지 않은 데이터가 호스트 환경으로 전달되어 파일에 기록되도록합니다. 그렇지 않으면 동작이 정의되지 않습니다.

POSIX는 대부분 C 표준을 따르지만이 텍스트를 C 확장으로 표시합니다.

[CX] 읽기 용으로 열린 스트림의 경우 파일이 아직 EOF에 있지 않고 파일이 검색 할 수있는 파일이면 기본 열린 파일 설명의 파일 오프셋이 스트림의 파일 위치로 설정되어야하며 스트림에 의해 다시 푸시 ungetc()되거나 스트림 ungetwc()에서 읽히지 않은 문자 는 버려집니다 (파일 오프셋을 더 변경하지 않고).

터미널은 검색 할 수 없습니다. 파이프도 소켓도 아닙니다.

Microsoft는 fflush(stdin)

Microsoft 및 Visual Studio 런타임은 fflush()입력 스트림 의 동작을 정의합니다 .

입력을 위해 스트림이 열려 fflush있는 경우 버퍼의 내용을 지 웁니다.

MM 노트 :

Cygwin은 fflush(stdin)입력을 지우지 않는 상당히 일반적인 플랫폼의 예입니다 .

이것이 내 의견 의이 답변 버전이 'Microsoft 및 Visual Studio 런타임'을 언급하는 이유입니다. 타사 C 런타임 라이브러리를 사용하는 경우 표시되는 동작은 해당 라이브러리에 따라 다릅니다.

Linux 문서와 연습이 서로 모순되는 것 같습니다.

놀랍게도 Linux는 명목상 그 행동을 문서화 fflush(stdin)하고 심지어 같은 방식으로 정의합니다 (기적의 기적).

입력 스트림의 fflush()경우 기본 파일에서 가져 왔지만 응용 프로그램에서 사용하지 않은 버퍼링 된 데이터를 삭제합니다.

나는 그것이 fflush(stdin)작동 것이라고 말하는 리눅스 문서에 약간 의아해하고 놀랐다 . 이러한 제안에도 불구하고 대부분 Linux에서는 작동하지 않습니다. 방금 Ubuntu 14.04 LTS에 대한 문서를 확인했습니다. 위에서 인용 한 내용을 말하지만 경험적으로는 작동하지 않습니다. 적어도 입력 스트림이 터미널과 같이 검색 할 수없는 장치 인 경우에는 작동하지 않습니다.

demo-fflush.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c; enter some new data\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

예제 출력

$ ./demo-fflush
Alliteration
Got A; enter some new data
Got l
$

이 출력은 Ubuntu 14.04 LTS 및 Mac OS X 10.11.2 모두에서 얻었습니다. 내 이해로는 Linux 매뉴얼이 말하는 것과 모순됩니다. 는 IF fflush(stdin)작업을했다, 나는 두 번째에 대한 정보를 얻기 위해 텍스트의 새로운 라인을 입력해야 getchar()읽을합니다.

POSIX 표준이 말하는 것을 감안할 때 더 나은 데모가 필요할 수 있으며 Linux 문서를 명확히해야합니다.

demo-fflush2.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c\n", c);
        ungetc('B', stdin);
        ungetc('Z', stdin);
        if ((c = getchar()) == EOF)
        {
            fprintf(stderr, "Huh?!\n");
            return 1;
        }
        printf("Got %c after ungetc()\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

예제 출력

검색 /etc/passwd가능한 파일입니다. Ubuntu에서 첫 번째 줄은 다음과 같습니다.

root:x:0:0:root:/root:/bin/bash

Mac OS X에서 처음 4 줄은 다음과 같습니다.

##
# User Database
# 
# Note that this file is consulted directly only when the system is running

즉, Mac OS X /etc/passwd파일 상단에 해설이 있습니다. 주석이 아닌 행은 일반 레이아웃을 따르므로 root항목은 다음과 같습니다.

root:*:0:0:System Administrator:/var/root:/bin/sh

Ubuntu 14.04 LTS :

$ ./demo-fflush2 < /etc/passwd
Got r
Got Z after ungetc()
Got o
$ ./demo-fflush2
Allotrope
Got A
Got Z after ungetc()
Got B
$

Mac OS X 10.11.2 :

$ ./demo-fflush2 < /etc/passwd
Got #
Got Z after ungetc()
Got B
$

The Mac OS X behaviour ignores (or at least seems to ignore) the fflush(stdin) (thus not following POSIX on this issue). The Linux behaviour corresponds to the documented POSIX behaviour, but the POSIX specification is far more careful in what it says — it specifies a file capable of seeking, but terminals, of course, do not support seeking. It is also much less useful than the Microsoft specification.

Summary

Microsoft documents the behaviour of fflush(stdin). Apparently, it works as documented on the Windows platform, using the native Windows compiler and C runtime support libraries.

Despite documentation to the contrary, it does not work on Linux when the standard input is a terminal, but it seems to follow the POSIX specification which is far more carefully worded. According to the C standard, the behaviour of fflush(stdin) is undefined. POSIX adds the qualifier 'unless the input file is seekable', which a terminal is not. The behaviour is not the same as Microsoft's.

Consequently, portable code does not use fflush(stdin). Code that is tied to Microsoft's platform may use it and it will work, but beware the portability issues.

POSIX way to discard unread terminal input from a file descriptor

The POSIX standard way to discard unread information from a terminal file descriptor (as opposed to a file stream like stdin) is illustrated at How can I flush unread data from a tty input queue on a Unix system. However, that is operating below the standard I/O library level.


According to the standard, fflush can only be used with output buffers, and obviously stdin isn't one. However, some standard C libraries provide the use of fflush(stdin) as an extension. In that case you can use it, but it will affect portability, so you will no longer be able to use any standards-compliant standard C library on earth and expect the same results.


Quote from POSIX:

For a stream open for reading, if the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be set to the file position of the stream, and any characters pushed back onto the stream by ungetc() or ungetwc() that have not subsequently been read from the stream shall be dis- carded (without further changing the file offset).

Note that terminal is not capable of seeking.

참고URL : https://stackoverflow.com/questions/2979209/using-fflushstdin

반응형