C,C++ & Linux

C/C++ setbuf(3) setvbuf(3)

KyooDong 2020. 5. 21. 10:14
728x90

함수 기능

파일의 버퍼를 바꿔주는 함수입니다.

 

버퍼 방식

버퍼 방식 매크로 설명
Full buffer _IOFBF 버퍼가 가득 차야 파일에 읽고 쓰는 방식으로 주로 일반 파일에 적용
Line buffer _IOLBF 버퍼에 개행 문자가 들어오면 파일에 읽고 쓰는 방식으로 표준 입출력 파일에 쓰임
None buffer _IONBF 버퍼를 사용하지 않고 바로바로 파일에 읽고 쓰는 방식으로 표준 에러 파일에 쓰임

 

setbuf() 의 경우 buf 인자에 NULL을 넣게 되면 None buffer를 의미하며 NULL이 아닌 값을 넣게 되면 해당 버퍼를 Full buffer 로  사용하게 됩니다. 단 fp 인자가 터미널인 경우 Line buffer 를 사용하게 됩니다. 이때 버퍼의 크기는 BUFSIZ 로 사용되며 이 크기는 시스템마다 다릅니다.

 

setvbuf() 는 setbuf() 와는 달리 버퍼의 크기와 그 모드를 지정할 수 있습니다.

buf 인자에 NULL을 넣게 되면 None buffer를 사용하게 되며 이때 mode와 size 는 무시됩니다.

NULL이 아닌 값을 넣게 되면 해당 버퍼를 지정된 mode 로 사용하게 됩니다.

mode의 인자로는 _IOFBF, _IOLBF, _IONBF 가 있습니다.

 

함수 원형

#include <stdio.h>

void setbuf(FILE *fp, char *buf);
int setvbuf(FILE *fp, char *buf, int mode, size_t size);

매개변수

fp

버퍼를 설정할 파일 포인터

 

buf

버퍼로 사용할 배열 공간 주소

 

mode

버퍼 모드

_IOFBF, _IOLBF, _IONBF 사용 가능

 

size

버퍼의 크기, 기본은 BUFSIZ

반환값

성공 시 0 리턴

에러 시 0이 아닌 값 리턴하고 errno 설정

예제

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    char buf[BUFSIZ];

    // stdout 같은 터미널은 Line buffer 로 지정됨
    // 따라서 \n 문자를 만날때 화면에 출력됨
    setbuf(stdout, buf);

    // 출력 x
    printf("Hello, ");
    sleep(1);

    // 출력 x
    printf("OSLAB!!");
    sleep(1);

    // Hello, OSLAB!!\n 한 번에 출력
    printf("\n");
    sleep(1);

    // None buffer 로 변경
    // 여기서부터는 매 라인마다 바로바로 출력됨
    setbuf(stdout, NULL);

    // How 출력
    printf("How");
    sleep(1);

    // are 출력
    printf(" are");
    sleep(1);

    // you? 출력
    printf(" you?");
    sleep(1);

    // \n 출력
    printf("\n");
    exit(0);
}

결과

 

예제2

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    char buf[BUFSIZ];
    int a, b;

    // buf 를 표준 입력의 버퍼로 지정
    // 터미널이므로 Line buffer 로 설정됨
    setbuf(stdin, buf);
    scanf("%d %d", &a, &b);

    // 새로운 버퍼로 지정된 buf를 출력
    for (int i = 0; buf[i] != '\n'; i++)
        putchar(buf[i]);

    putchar('\n');
    exit(0);
}

결과

예제3

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void ssu_setbuf(FILE *fp, char *buf) {
    size_t size;
    int fd;
    int mode;

	// 파일 포인터로부터 파일 디스크립터를 뽑아내는 함수
    fd = fileno(fp);
	
	// 터미널인지 확인해주는 함수
    if (isatty(fd))
		// 터미널인 경우 라인 버퍼
        mode = _IOLBF;
    else
		// 아닌 경우 풀 버퍼
        mode = _IOFBF;

	// buf 인자가 널인 경우
    if (buf == NULL) {
		// 넌 버퍼 모드
        mode = _IONBF;
        size = 0;
    }
    else
        size = BUFSIZ;

	// 버퍼 설정
    setvbuf(fp, buf, mode, size);
}

int main(int argc, char *argv[]) {
    char buf[BUFSIZ];
    FILE *fp;

	// argv[1] 에 다른 터미널의 터미널 파일 아이디를 넣을 것입니다.
    if ((fp = fopen(argv[1], "w")) == NULL) {
        fprintf(stderr, "file open error\n");
        exit(1);
    }

	// 따라서 setbuf 를 하면 isatty 에서 true로 판명되고, line buffer 로 설정됩니다.
    ssu_setbuf(fp, buf);
    fprintf(fp, "Hello, ");
    sleep(1);

    fprintf(fp, "UNIX!!");
    sleep(1);
    
	// line buffer 이기 때문에 3초 대기 후 Hello, UNIX!!\n가 한번에 출력
    fprintf(fp, "\n");
    sleep(1);

	// None buffer로 교체
    ssu_setbuf(fp, NULL);
	
	// None 버퍼기 때문에 대기 없이 바로바로 출력
    fprintf(fp, "HOW");
    sleep(1);

    fprintf(fp, " ARE");
    sleep(1);

    fprintf(fp, " YOU?");
    sleep(1);

    fprintf(fp, "\n");
    sleep(1);
    exit(0);
}

결과

실습 시 두 개의 터미널이 필요합니다.

한 터미널에서 tty 명령어를 통해 어떤 터미널 파일을 쓰고 있는지 확인합니다,

저의 경우에는 /dev/ttys002 가 되겠습니다.

./a.out <본인 터미널 파일> 입력하시면 위 터미널에 Hello, UNIX!!와 HOW ARE YOU? 가 주입됩니다.

 

 

 

 

리눅스시스템프로그래밍 저자 : 홍지만
https://book.naver.com/bookdb/book_detail.nhn?bid=14623672

책에 기술된 예제 프로그램입니다. 책 내부에는 훨씬 더 많은 자료가 있습니다. (개인적으로 좋았습니다.)