입력, 출력, 오류를 위한 표준 스트림
**표준 스트림**(standard streams)은 특정한 프로그래밍 언어 인터페이스뿐 아니라 유닉스 및 유닉스 계열 운영 체제(어느 정도까지는 윈도우에도 해당함)에서 컴퓨터 프로그램과 그 환경(일반적으로 단말기) 사이에 미리 연결된 입출력 통로를 가리킨다.

일반적으로 유닉스에서 동작하는 프로그램은 실행 시 세 개의 스트림이 자동으로 열린다. 이를 표준 스트림이라고 부른다. 하나는 입력을 위한 스트림(Standard input, STDIN, 0), 하나는 출력을 위한 스트림(Standard Output, STDOUT, 1), 하나는 오류 메시지를 출력하기 위한 스트림(Standard Error, STDERR, 2)이며, 이 세 개의 표준 스트림은 사용자의 터미널에 부착된다.

보통 입출력은 물리적으로 연결된 시스템 콘솔의 키보드와 모니터를 통해 일어나는데, **표준 스트림**은 이것을 추상화한 것이다. 어떤 명령이 대화형 셸을 통해 실행될 때, 일반적으로 명령의 스트림은 셸이 실행중인 텍스트 터미널에 연결된다. (그러나 이는 **파이프**와 같은 **리다이렉션**을 통해 전환될 수 있다.) 더 일반적으로 말하자면, **자식 프로세스는 부모 프로세스의 표준 스트림을 상속 받는다**고 할 수 있다.

통상, 터미널에 로그인 셸이 먼저 기동되고, (사용자 인증이 끝나면) 대화형 셸이 기동된다. 이때 자동으로 터미널에 부착된 세 개의 표준 스트림이 상속된다. 이후, 셸에서 실행되는(exec) 모든 명령들은, 셸을 부모 프로세스로 삼아 세 개의 표준 스트림을 다시 상속 받는다.

표준 C 실행 라이브러리의 <stdio.h> 헤더에서 stdin, stdout, stderr 로 정의되며, <unistd.h>[깨진 링크(과거 내용 찾기)] 에 의해 파일 디스크립터 0, 1, 2 로 표현하기도 한다.

유닉스의 영향을 강하게 받은 리눅스에서도 표준 스트림의 파일 서술자가 선점되어 있다.

배경
--

유닉스 이전의 대부분의 운영 체제에서, 프로그램은 명시적으로 적절한 입력 장치와 출력 장치에 연결해줄 필요가 있었다. 이 작업은 각 OS 마다 처리 방식이 달랐기 때문에 매우 방대한 작업이었다. 수많은 시스템에서 환경 설정을 제어하거나, 파일 테이블에 접근하거나, 필요한 데이터 셋을 결정하기 위해 펀치 카드 리더기나 자기 테이프 드라이브, 라인 프린터, 카드 펀치, 대화식 터미널을 적절하게 제어할 필요가 있었다.

이런 상황에서, 유닉스의 획기적인 발전 중 하나는 **장치의 추상화**였다. 프로그램은 더 이상 어떤 장치와 연결되는지 알 필요가 없었다. 유닉스는 기존의 복잡성을 **데이터 스트림**이라는 개념으로 해소 시켰다. 데이터 스트림은 순차적인 데이터 바이트들을 파일의 끝(EOF)까지 읽는다. 이런 방식으로, 프로그램은 쓸 데이터가 얼만큼 남았는지, 혹은 어떤 식으로 묶여있는지 알 필요 없이 필요한 데이터를 쓸 수 있었다.

또 다른 유닉스의 획기적인 발전은, **자동으로 연결되는 입출력 장치**였다. 프로그래머나 프로그램에서 입출력을 사용해야 할 때, 입출력 장치를 연결하기 위한 그 어떤 추가 작업도 필요하지 않게 되었다. 이전의 운영 체제들에서 입출력 장치를 연결하기 위해 복잡한 작업 제어 언어가 필요하거나, 그와 동일한 역할을 하는 프로그램이 필요했던 것과는 대조적이다.

유닉스에서 표준 스트림이 지원된 이후로, 유닉스 C 실행 환경에서도 이를 잘 지원해야 할 의무가 생겼다. 그 결과로, 대부분의 C 실행 환경에서 (이후의 C의 파생 언어들을 포함하여) 운영 체제와 상관없이 동일한 기능을 제공하게 되었다.

응용 프로그램
-------

텍스트 터미널 상에서 동작하는 세 개의 프로그램이 파이프라인으로 연결된 모습
일반적으로 사용자들은 표준 스트림이 입출력 장치에서 문자들이 오가는 매개체로만 사용되는 것으로 알고 있다. 보통 이렇게 표준 스트림이 입력 장치와 출력 장치에서 사용될 때는, Latin-1 이나 UTF-8 로 미리 인코딩된 문자열이 오간다.

그러나 표준 스트림이 응용 프로그램에서 사용될때, 이 스트림들은 연쇄적으로 연결될 수 있다. 예를 들어 어떤 프로그램의 출력은 다른 프로그램의 입력으로 쓰일 수 있는데, 잘 알려진 예는 `pager` 나 `more` 유틸리티이다. 사용자는 다른 응용 프로그램의 출력 스트림을 이런 유틸리티의 입력 스트림으로 삼아, 어떤 식으로 화면에 출력할지 제어할 수 있다.

표준 스트림은 보통 텍스트를 포함하는 대화식 사용에서 많이 활용되지만, 가끔은 이진 데이터를 전송하는 데에도 쓰일 수 있다.

표준 입력 (stdin)
-------------

표준 입력은 프로그램으로 들어가는 데이터(보통은 문자열) 스트림이다. 프로그램은 *read* 명령을 이용하여 데이터 전송을 요청한다. 모든 프로그램이 입력을 요구하는 것은 아니다. 이를테면 `dir`이나 `ls` 프로그램(디렉터리에 들어 있는 파일 이름을 보여 주는 명령)은 실행시 옵션과 같은 명령줄 매개변수를 받을 수는 있으나, 동작 중에 데이터 스트림의 입력 없이 명령을 수행한다.

별도의 리다이렉션 없이 프로그램을 시작한 경우, 표준 입력 스트림은 키보드에서 받아온다.

표준 입력을 위한 파일 서술자는 0이다. POSIX `<unistd.h>` 정의는 `STDIN_FILENO`이다. 이에 해당하는 `<stdio.h>` 변수는 `FILE* stdin;`이다. 이와 비슷하게 `<iostream>`에서는 `std::cin`이다.

표준 출력 (stdout)
--------------

표준 출력은 프로그램이 출력 데이터를 기록하는 스트림이다. 프로그램은 `write` 명령을 이용하여 데이터 전송을 요청한다. 모든 프로그램이 출력을 요구하는 것은 아니다. 이를테면 파일 이름 바꾸기 명령(일반적으로 `mv`, `move`, `ren`)은 명령 수행이 성공적이어도 아무 메시지도 나타내지 않는다.

리다이렉션 없이 표준 출력은 프로그램을 시작한 텍스트 터미널이 된다.

표준 출력을 위한 파일 서술자는 1이다. POSIX `<unistd.h>` 정의는 `STDOUT_FILENO`이다. 이에 해당하는 `<stdio.h>` 변수는 `FILE* stdout;`이다. 이와 비슷하게 `<iostream>`에서는 `std::cout`이다.

표준 오류 (stderr)
--------------

표준 오류는 프로그램이 오류 메시지나 진단을 출력하기 위해 일반적으로 쓰이는 또다른 출력 스트림이다. 표준 출력과는 독립적인 스트림이며 별도로 리다이렉트될 수 있다.

표준 오류를 위한 파일 서술자는 2이다. POSIX `<unistd.h>` 정의는 `STDERR_FILENO`이다. 이에 해당하는 `<stdio.h>` 변수는 `FILE* stderr;`이다. `<iostream>` 표준 헤더는 이 스트림에 관련하여 두 개의 변수 `std::cerr`과 `std::clog`를 제공한다. 전자의 것은 버퍼링이 되지 않지만 후자는 버퍼링을 이용한다.

참고 문헌
-----

* *KRONOS 2.1 Reference Manual*, Control Data Corporation, Part Number 60407000, 1974
* *NOS Version 1 Applications Programmer's Instant*, Control Data Corporation, Part Number 60436000, 1978
* Level 68 Introduction to Programming on MULTICS Archived 2021년 2월 25일 - 웨이백 머신, Honeywell Corporation, 1981
* Evolution of the MVS Operating System, IBM Corporation, 1981
* *Lions' Commentary on UNIX Sixth Edition*, John Lions, ISBN 1-57398-013-7, 1977
* Console Class, .NET Framework Class Library, Microsoft Corporation, 2008