C 언어 | 고급 기능 | 표준 입출력 - fprintf(), fscanf()

커멘드 출력과 키보드 입력은 표준 출력이나 표준 입력라는 특별한 FILE 구조체의 포인터로 정의되어 있다.

기본 입출력

지금까지 printf() 함수는 화면에 문자열을 표시하고, scanf() 함수는 키보드에서 문자열을 입력할 수 있다고 설명하였다. 이는 기본적으로 틀린 것은 아니지만 정확한 표현은 아니다. 입출력에 대해 제대로 이해하고 있는 기술자라면 “printf()는 표준 출력에 문자열을 출력하고, scanf() 함수는 표준 입력에서 문자열을 입력한다"고 표현할 것이다.

실은 C 언어에서는 화면이나 키보드에 대한 데이터 입출력을 파일과 같이 조작할 수 있다. 앞전에 설명한 바와 같이 입출력은 모두가 스트림 개념으로 통일되어 있기 때문이다. 개발자는 문자열의 입출력을 파일에서도 화면에서도 네트워크에서도 동일한 방식으로 개발할 수 있는 것이다. 그러나 자주 입출력을 할 수있는 디바이스(device), 즉 화면 출력과 키보드 입력은 특별 취급된다. 많은 시스템에는 디스플레이를 표준 출력, 키보드를 표준 입력으로 정하고 있다.

표준 출력은 프로그램이 응용 프로그램 사용자에게 메시지를 표시할 경우에, 문자열을 출력할 위치를 나타내고, 표준 입력은 어떤 정보를 입력할 경우에 대상이 되는 장치를 나타낸다. 이 외에도 에러 메시지를 표시하는 전용 표준 에러라는 디바이스도 준비되어 있다. 표준 에러도 보통 디스플레이이다.

표준 출력과 표준 입력, 표준 오류는 프로그램이 결정해야하는 것은 아니다. 이러한 시스템의 이용자가 설정으로 결정해야 문제이다. 어떤 이용자는 프로그램이 화면에 출력하는 문자를 프린터와 로그 파일에 저장하고 싶을지도 모른다. 이 경우는 프로그램을 다시 작성하지 않고, 표준 출력을 변경하면 된다. 일반적으로 표준 출력 및 표준 입력은 시스템 설정으로 변경할 수 있다. 이것을 리디렉션이라고 한다. 리디렉션에 대해서는 사용하는 시스템의 도움말을 참조하자.

printf() 함수는 화면에 문자를 표시하는 함수가 아닌 표준 출력에 문자열을 표시하는 함수이며, scanf() 함수는 표준 입력에 입력하라는 함수이었다. 예를 들어, Microsoft MS-DOS를 사용하는 경우는 커멘드 라인에서 다음과 같이 프로그램을 실행 시켜서 표준 출력을 변경할 수 있다.

C:\...>dir > dir.txt

이것은 dir 명령을 사용하여 현재 디렉터리의 정보를 표시하고 있는데, 화면에 표시되어야 할 문자열이 표시되지 않고 dir.txt라는 파일이 생성된다. 이 파일이 표준 출력으로 취급되고, 문자열이 저장된다.

이렇게 문자열을 결과로 출력하는 커멘드 레벨의 응용 프로그램의 경우는 파일 작업을 할 필요는 그다지 없다. 강제로 파일 작업을 수행하는 것보다도, 오히려 이용자에게 출력하는 곳을 맡긴 것이 유연하고 사용하기 쉬운 소프트웨어가 될 것이다.

표준 출력과 표준 입력, 표준 에러도 스트림이므로 파일 관련 함수로 처리 할 수 있다. 파일 관련 함수로 입출력을 하려면 FILE 구조체에 대한 포인터가 필요하는데, stdio.h 헤더 파일에서 아래의 스트림 포인터가 제공되고 있어서 이들을 연결한 표준 스트림에 액세스할 수 있다.

stdin 상수

FILE *stdin;

stdout 상수

FILE *stdout;

stderr 상수

FILE *stderr;

이 포인터 상수에 새로운 값을 대입할 수 없다. stdin 상수는 표준 입력, stdout 상수는 표준 출력, stderr 상수는 표준 에러로 되어 있다. 함수 등이 에러를 반환하고 프로그램을 성공적으로 수행할 수 없다는 것을 사용자에게 통지하는 경우, 지금까지는 printf() 함수를 사용했지만, 정확하게는 stderr에 출력해야 한다.

코드1

#include <stdio.h>

int main(int argc , char *argv[]) {
  char chError[0xFF];

 fputs("출력하는 에러 문자열을 입력해 주세요.>" , stdout);
 fgets(chError , 0xFF , stdin);
  fputs(chError , stderr);

  return 0;
}

코드1는 stdout, stdin, stderr를 이용하여 상호 처리를 하고 있다. 예를 들어 첫번째 fputs() 함수는 표준 출력에 문자열을 표시하고 있다. 이것은 평소라면 printf() 함수를 사용하지만, 이러한 파일 입출력 함수로 정의된 표준 입출력 스트림을 사용하여 프로그램할 수 있다.

그러나 이러한 함수를 사용하면 문자열 단위 입출력 밖에 할 수 없다. printf()와 scanf() 함수와 같은 서식 제어을 파일 입출력 함수으로 한다면 편리하다. 실은 스트림을 지정할 수 있는 fprintf() 함수와 fscanf() 함수라는 것이 준비되어 있다.

fprintf() 함수

int fprintf( FILE *stream, const char *format [, argument ]...);

fscanf() 함수

int fscanf( FILE *stream, const char *format [, argument ]... );

기본적으로, 첫번째 인수에 입출력 대상의 스트림을 지정하는 것을 제외하고는 printf()와 scanf() 함수와 동일하다. fprintf() 함수는 성공하면 출력한 문자 수를 실패하면 음수를 반환한다. fscanf() 함수는 성공하면 입력된 데이터의 개수를, 실패하면 EOF를 반환한다. 이 함수를 사용하면 파일 입출력에서도 printf()와 scanf() 함수처럼 프로그램할 수 있다. 반대로

printf("Kitty on your lap");

fprintf(stdout , "Kitty on your lap");

는 같다고 생각할 수 있다.

코드2

#include <stdio.h>

int main() {
  char chSelect;
  fprintf(stdout , "출력을 선택하세요. o/e>");
  fscanf(stdin , "%c" , &chSelect);

 switch(chSelect) {
  case 'e':
 case 'E':
   fprintf(stderr , "Kitty on your lap\n");
   break;
  case 'o':
 case 'O':
   fprintf(stdout , "Kitty on your lap\n");
   break;
  }

 return 0;
}

코드2는 fscanf() 함수으로 stdin 상수를 매개 변수로 지정하고 있기 때문에 scanf() 함수처럼 표준 입력에서 데이터를 읽어들인다. 프로그램은 사용자에게 표준 출력 또는 표준 에러를 어느쪽으로 출력을 선택하고 있다. 그 후에 fprintf() 함수를 사용하여 표준 출력이나 표준 에러에 문자열을 출력한다.

이 프로그램에는 단순히 표준 입력과 표준 출력에 대해 출력하고 있는데, 매개 변수에 파일을 가리키는 FILE 구조체의 포인터를 설정하면, 서식 지정을 이용하여 데이터의 쓰기와 읽기를 할 수 있다.




최종 수정 : 2017-11-26