C 언어의 Stream
- 외부 장치와의 입출력에 스트림을 이용하며 일반적으로, 바이트(문자) 및 바이너리(이진)으로 구분 처리한다.
- printf()와 scanf() 와 같은 콘솔 입출력의 'input stream'과 'output stream'이 자동으로 생성되고, 소멸된다.
1. C 언어 표준 입출력 스트림
스트림 | 설명 | 장치 |
stdin | 표준 입력 | 키보드 |
stdout | 표준 출력 | 화면 |
stderr | 표준 에러 | 화면 |
: 표준 스트림 : stdin, stdout, stderr . 따로, 스트림을 열 필요 없이 바로 사용 가능함
: 파일 스트림 : 파일 입출력시, 자동으로 스트림이 생성되지 않고, 먼저 스트림을 생성시켜야 함
: 문자를 unsigned char 형식으로 다룬다. 리턴은 int 형식으로 변환되므로 0이하의 음수일 수 없다.
2. 문자 1개 단위로 입력 - putchar( ), putc( ), fputc( )
#include <stdio.h>
int putchar(int c);
int putc(int c, FILE *stream);
int fputc(int c, FILE *stream);
- putchar( ) 함수는 stdout 스트림에 쓴다.
- putc( ), fputc( )는 동일한 작업을 하며, 선언된 임의의 스트림에 쓴다는 점이 putchar( ) 함수와 다르다.
- putc( )는 매크로, fputc( )는 함수로만 정의되어 있어 putc( )가 빠르지만, fputc는 매크로의 잠재적인 문제점으로부터 자유롭다.
- 문자는 스트림의 끝에 추가된다.
3. 문자 1개 단위로 출력 - getchar( ), getc( ), fgetc( )
#include <stdio.h>
int getchar(void);
int getc(FILE *stream);
int fgetc(FILE* stream);
// 성공 : 읽어 들인 문자
// 실패 : EOF
- getchar( )는 문자열 1개를 stdin에서 읽는다.
- getc( )와 fgetc( )는 문자열 1개를 선언된 임의의 스트림에서 읽는다.
- fgets()는 한 문자씩 읽어 들이며, 다음 문자를 가리키는 위치 지시자의 포인터 값을 증가시킨다.
4. 한줄 단위의 입력 - puts( ), fputs( )
#include <stdio.h>
int puts(const char *string);
int fputs(const char *string, FILE *stream);
문자열을 NULL('\0') 까지, NULL 제외하고
puts( )는 개행 문자('\n') 추가하여, stdout 에 쓴다.
fputs( )는 개행 문자('\n') 추가 않고, 선언된 임의의 스트림에 쓴다.
puts( )는 개행 문자('\n')가 추가되어, 두번 개행되지 않도록 신경써야 하며,
fputs( )는 개행 문자('\n')와 NULL 추가되지 않아, 문자열[길이]='\0' ,과 같이 임의로 구분해야 한다.
5. 한줄 단위의 출력 - gets( ), fgets( )
#include <stdio.h>
char *gets(char *buffer);
char *fgets (char *string, int n, FILE *stream);
문자열을 개행('\n') 까지
gets( )는 개행 제거, NULL('\0') 추가하고, stdin에서 읽어들인다.
fgets( )는 개행 포함, NULL('\0') 추가하고, 선언된 임의의 스트림에서 읽어들인다.
gets( )와 fgets( )는 자동으로 NULL('\0')이 추가된다.
fgets( )에서 설정한 길이에 따라 개행('\0')추가 또는 NULL 문자와 개행 문자 교환 할 필요가 있다.
참고, scanf( ) 의 경우 개행 문자, ' ' 와 '\t' 에 의해 입력이 끝난다.
6. fgets( ) 개행('\0')과 NULL 처리
fgets( ) 경우, 설정한 크기만큼 읽어들여, buffer의 오버플로에 대해 안전하다.
#include <stdio.h>
#include <string.h>
int main(void)
{
char buf[5];
printf("최대 입력 크기는 5입니다.\n");
printf("입력 >> ");
fgets(buf, sizeof(buf), stdin); //입력 스트림에서 문자열 읽기
printf("출력 >> [0] [1] [2] [3] [4]\n");
printf("출력 >> %d %d %d %d %d\n", buf[0], buf[1], buf[2], buf[3], buf[4]);
printf("출력 >> %s \n", buf);
printf("길이 >> %d \n", strlen(buf));
return 0;
}
'\n' 개행 문자를 '\0' NULL 문자로 변경하는 방법
123\0 이아니라,
123\n\0 이 받아진다는 것이다.
buf[strlen(input) - 1] = '\0';
// input에 포함된 '\n' 개행문자를, '\0' NULL 로 변경
7. scanf( )
scanf()는 stdin의 버퍼에서 서식 시정자에 맞는 값만을 가져온다.
예를 들어 123을 치고 엔터를 쳤다면 123이라는 값을 가져와서 %d로 해석한다.
이 때문에 scanf()는 개행 문자('\n')와 공백에 관한 문제가 생긴다.
scanf() 의 반환값은, 타입에 맞는 문자의 갯수
8. getch( ), getche( )
getch(), getche() 는 버퍼를 사용하지 않고, 키보드를 눌렀다가 떼는 동시에 그 값을 가져가 버린다.
그렇기 때문에 잘못 입력한 값을 수정할 수 없고, 백스페이스를 누르면 삭제되기는 커녕 백스페이스 값도 입력된다.
9. stderr( )
에러 메시지 출력을 제때 또는 제대로 못하게 되는 경우를 방지하기 위해, stderr 같은 경우는 버퍼 없이 바로 출력 합니다.
따라서 어떤 상황에서도 가장 빠르게 에러 메시지를 출력 할 수 있다.
10. EOF
End OF File의 약자로서, "파일의 끝에 도달해서 더이상 읽을 내용이 없다." 를 정의해 놓은 상수다.
fputc(), fgetc()의 경우, 호출 실패시 EOF를 반환 하도록 되어 있다.
EOF는 -1로 정의된 상수로, 반환형이 char형일 경우, unsigned char로 처리하는 컴파일러로 인해 문제가 발생한다.
이를 방지하기위해 어떠한 상황에서도 -1을 인식할 수 있는 int형을 반환형으로 정의한다.
11. 표준 입출력
운영체제들은 다양한 외부 장치를 사용하고 제어해야 한다.
Unix 운영체제는 이를 동일한 형식으로 관리하기 위해, 외부 장치를 "파일 시스템"처럼 사용할 수 있도록 설계했다.
키보드를 예로, 키보드 또한 외부 장치이기 때문에, Unix에서는 이를 파일에서 데이터를 읽는 것처럼 구성했다.
표준 스트림 | 일반 스트림 | 설명 | |
타입 x 문자열 형태 |
getchar() putchar() gets() puts() |
fgetc(FILE *f, ..) fputc(FILE *f, ..) fgets(FILE *f, ..) fputs(FILE *f, ..) |
문자 입력 문자 출력 문자열 입력 문자열 출력 |
타입 o 단어 형태 |
scanf() printf() |
fscanf(FILE *f, ...) fprintf(FILE *f, ...) |
타입 지정 입력 타입 지정 출력 |
__acrt_iob_func()
C 언어는 __acrt_iob_func() 함수를 stdin, stdout 으로 재정의해서 사용한다.
FILE* __cdecl __acrt_iob_func(unsigned);
#define stdin (__acrt_iob_func(0)) // stdin = 'standard input' 표준 입력
#define stdout (__acrt_iob_func(1)) // stdout = 'standard output' 표준 출력
FILE *p_input = __acrt_iob_func(0); // 표준 입력에 대한 포인터 의미
FILE *p_input = stdin;
FILE *p_output = __acrt_iob_func(1); // 표준 출력에 대한 포인터 의미
FILE *p_output = stdout;
#include <stdio.h>
int main(void)
{
FILE* pStream = stdin;
printf("stdin의 크기\t: %lu바이트\n", sizeof(pStream)); // 8바이트
pStream = stdout;
printf("stdout의 크기\t: %lu바이트\n", sizeof(pStream)); // 8바이트
return 0;
}