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