Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

\r 과 \n 의 차이점이 뭔가요?

12 views
Skip to first unread message

김승범

unread,
May 17, 2003, 12:29:52 AM5/17/03
to
Puhaha wrote:
>
> 비표준인 getch()에 대한 설명에서
> ... 버퍼를 사용하는 문자입력 함수는 개행 문자를 자동으로 문장 진행 문자로
> 변환하므로 프로그램에서는 엔터키의 입력을 확인하기 위해 \n과 비교해야한다.
> 그러나 버퍼를 사용하지 않는 입력 함수는 개행 문자를 문장 진행 문자로
> 변환하지 않으므로 개행 문자는 \r 로 입력된다.
>
> 간단한 검색을 해보니 개행 문자와 문장 진행 문자가 같은 뜻인 것 같습니다.
> 자연 위의 글이 이해가 되지 않아서 대충 어림짐작해보니 '버퍼를 사용하지 않는
> 입력함수는 버퍼를 사용하는 입력함수처럼 엔터키로 끝을 확인하지 않으므로 \n
> 대신 \r 을 사용한다' 인 것 같습니다.
>
> 제 어림짐작이 맞나요?

정말 검색을 해 보니 '개행 문자'와 '문장 진행 문자'가 서로 다른 곳에서
각각 'new line character'를 의미하는 것으로 쓰이고 있는 것 같네요.
어떤 권위 있는 정의가 있는지는 잘 모르겠습니다만..

입출력 함수는 크게 스트림을 대상으로 하는 것과 콘솔을 대상으로 하는
것으로 나눌 수 있고, 스트림에는 텍스트 스트림과 바이너리 스트림이
있습니다. 위에서 말씀하신 '버퍼를 사용하는', '버퍼를 사용하지 않는'은
잘못된 분류이고, 이들은 각각 '텍스트 스트림 대상의', '텍스트 스트림
대상이 아닌' 정도로 바뀌어야 맞는 설명이 되겠습니다.

C 표준 라이브러리에 정의되어 있는 입출력 함수들은 모두 (명시적으로든
암시적으로든) FILE 구조체를 통해 입출력을 수행하는 스트림 대상 입출력
함수입니다. 이들은 setbuf/setvbuf 함수를 통해 버퍼링 특성이 변경될 수
있지만 그렇다고 입출력 내용이 영향을 받지는 않습니다. 그리고 그 대상이
텍스트 스트림이라면 버퍼링 특성에 관계 없이 다음과 같은 변환이 구현체에
의해 자동으로 수행됩니다.

실제 입출력이 수행되는 장치에서는 줄의 끝(end of line; EOL)이 서로 다른
방식으로 표현될 수 있고, 여러 문자로 표현될 수도 있습니다. 예컨대

UNIX : EOL = LF * LF(line feed) = ASCII #10
Macintosh : EOL = CR * CR(carriage return) = ASCII #13
MS-DOS/Windows : EOL = CR + LF

이라고 합니다. 이 밖에도 다른 경우도 있을 수 있겠고요.

하지만 C 프로그램이 텍스트 스트림을 통해서 입출력을 수행한다면 이러한
다양한 EOL 문자열은 모두 하나의 NL(new line) 문자 '\n'으로 변환되기
때문에 위와 같은 차이점을 일일이 신경쓸 필요가 없습니다. 즉 윈도우에서
파일에 CR, LF 두 문자가 있을 때 이를 fgetc()로 읽으면 하나의 NL 문자
'\n'이 읽히고, 하나의 NL 문자 '\n'을 fputc()로 쓰면 파일에는 CR, LF
두 문자가 기록되는 것입니다. 따라서 C 프로그램에서는 줄의 끝은 무조건
NL('\n')이라고만 생각하면 됩니다.

(여기서 주의할 것은, LF 및 CR은 ASCII에 정의되어 있고 코드값도 얼마라고
정해져 있는 구체적인 문자인 반면, NL('\n')은 C 표준에 이름과 효과만으로
정의되어 있고 코드값도 얼마라고 정의되어 있지 않은 추상적인 문자라는
것입니다. 즉 이 두 가지는 서로 다른 차원에 살고 있는 문자들입니다.)

반면 입출력 대상이 바이너리 스트림이거나 콘솔인 경우 위와 같은 변환이
수행되지 않습니다. 이는 C 프로그램에서 추상적인 NL 문자('\n') 대신
물리적인 코드값을 직접 다루어야 한다는 것을 의미합니다. 그리고 '\n',
'\r' 등을 사용하더라도 이들이 더 이상 추상적인 의미로 사용되는 것이
아니라 구현체에 따라 정해져 있는 물리적인 코드값(예컨대 '\n'==10,
'\r'==13, '\a'==7 등)의 의미로만 사용되게 됩니다. 그리고 입력 대상에서
입력되고 출력 대상으로 출력되는 값도 줄바꿈 등의 추상적인 의미가 아닌
코드값의 의미만 갖게 되지요.

예컨대 getch() 등의 함수로 콘솔 입력을 대상으로 입력을 받는다면,
사용자가 엔터(Enter) 키를 누를 때 입력되는 값은 더 이상 줄바꿈 등의
추상적인 의미가 아니라 구현체에 의해 정해진 13이라는 코드의 의미만 갖게
됩니다. 따라서 당연히 C 프로그램에서도 이를 13이라는 코드의 의미로
받아들여 처리해야 합니다. 다만 구현체에서 '\r'의 코드값 또한 13으로
정의해 놓았다면 13이라는 (얼핏 보면 무슨 뜻인지 잘 모를) 숫자 상수 대신
'\r'이라는 (조금 더 의미 있어 보이는) 문자 상수를 사용할 수 있겠습니다만,
이는 어차피 필연적인 것은 아니고 구현체에 따라 달라질 수 있는 내용입니다.
그리고 콘솔을 대상으로 입출력한다면 어차피 엔터 키 외에도 '\X' 형태의
문자 상수로 모두 다룰 수 없는 다양한 입력을 받아 처리해야 할 것이니
이들을 모두 코드값 숫자 상수로 다루는 것이 나을 수도 있겠고요.

결론적으로, 추상적인 의미의 줄바꿈(NL) 문자와 구체적인 CR, LF 문자를
잘 구분하고 이들 사이의 변환(mapping)을 잘 이해하셔야 하겠습니다.
제가 드린 설명이 도움이 되었으면 좋겠습니다.

>
> ps-게시물 제목에선 슬러시가 그대로 나오는데 본문에선 \ 이렇게 나오네요. 혹시
> 슬러시가 그대로 나오게 하는 방법이 있나요?

말씀하신 문자의 정확한 이름은 백슬래시(backslash)입니다.

같은 코드값에 대해 ISO 646(=US-ASCII)에서는 슬래시('/')를 뒤집어 놓은
모양인 백슬래시 기호를 할당해 놓았지만 KS X 1003 (및 이를 포함하는
EUC-KR)에서는 원화 기호를 할당해 놓았기 때문에 그렇습니다. 즉 일반적으로
한국어를 사용하는 환경에서는 원화 기호가 보이는 것이 원칙적으로 맞는
것입니다. 사용하시는 프로그램에서 인코딩이나 글꼴을 바꾸면 백슬래시
기호가 보일 지도 모르겠습니다.

--
김승범

Luis Ahn

unread,
May 17, 2003, 12:22:54 PM5/17/03
to
.


Jun Woong

unread,
May 18, 2003, 2:16:54 AM5/18/03
to

"김승범" <musi...@bawi.org> wrote in message news:3EC5BAC0...@bawi.org...

> Puhaha wrote:
> >
> > 비표준인 getch()에 대한 설명에서
> > ... 버퍼를 사용하는 문자입력 함수는 개행 문자를 자동으로 문장 진행 문자로
> > 변환하므로 프로그램에서는 엔터키의 입력을 확인하기 위해 \n과 비교해야한다.
> > 그러나 버퍼를 사용하지 않는 입력 함수는 개행 문자를 문장 진행 문자로
> > 변환하지 않으므로 개행 문자는 \r 로 입력된다.

책에서 이루어지는 설명인지요? 또한, 동일한 설명이 표준 함수에 대해서도
존재하는지 궁금합니다.

stream 의 특성에는 buffered (2 종류)/unbuffered, text/binary,
byte-oriented/wide-oriented 가 있습니다. 파일을 open 함으로써 stream
과 file 을 연결할 수 있는 것이며 현재 문맥에서 문제가 되고 있는 stdio
는 기정의된 stream 중 하나입니다. 따라서, orientation 을 제외한 총 4가
지의 조합이 가능합니다. 개행문자의 외부 표현과 관련된 문제는
buffered/unbuffered 특성이 아닌 text/binary 특성과 관련된 것이므로 인
용하신 내용이 잘못되었다고 볼 수 있습니다. 물론, getch() 함수가 애초에
확장이므로 표준의 이와 같은 개념이 그대로 적용된다고도, 또 표준 IO 함
수에 주어지는 제한이 그대로 적용된다고도 단언할 수 없습니다만...

> >
> > 간단한 검색을 해보니 개행 문자와 문장 진행 문자가 같은 뜻인 것 같습니다.
> > 자연 위의 글이 이해가 되지 않아서 대충 어림짐작해보니 '버퍼를 사용하지 않는
> > 입력함수는 버퍼를 사용하는 입력함수처럼 엔터키로 끝을 확인하지 않으므로 \n
> > 대신 \r 을 사용한다' 인 것 같습니다.
> >
> > 제 어림짐작이 맞나요?
>
> 정말 검색을 해 보니 '개행 문자'와 '문장 진행 문자'가 서로 다른 곳에서
> 각각 'new line character'를 의미하는 것으로 쓰이고 있는 것 같네요.
> 어떤 권위 있는 정의가 있는지는 잘 모르겠습니다만..

현재 OP 께서 기술하신 문제는 '\n' 문자의 외부 표현 문제로서 아래 이어
서 설명하신대로 이해하는 것이 합당합니다만, 우리말로 흔히 "개행문자"
라고 번역되는 "newline" 이라는 용어에 잘 알려지지 않은 모호성이 있기에
이를 소개할까 합니다. newline 은 다음 줄로 커서 등을 옮기는 linefeed
를 의미하는데 사용되기도 합니다 - 즉, 다음 줄로의 이동만이 있을뿐 초기
위치로의 이동이 포함되지는 않습니다. 실례로 ANSI X3.4 (ASCII) 는 코드
0x0A 에 해당하는 문자를 linefeed 혹은 (C 에서 '\n' 가 의미하는 행동의)
newline 로 정의하고 있습니다 - 다수의 terminal 에서는 linefeed 기능을
수행하며, UNIX 에서는 newline 의 기능을 수행합니다. 반면, ANSI X3L2 에
서는 newline 이라는 용어를 linefeed 기능을 가리키는데 사용합니다. 또한
ISO/IEC 646 에서는 각각 LF 와 CR 로 기술되는 두 행동을 묶어 하나로 사
용하는 것을 구식 기술로 규정하고 있습니다 (deprecated). 하지만, C
Community 에서는 오래 전부터 newline 이라는 용어를 그 두 행동의 조합으
로 사용하고 있었고, 다만 '\n' 이 의미하는 문자의 실제 외부 표현이
implementation 에 따라 다를 수 있다는 사실이 그리 어렵지 않게 받아들여
지고 있었기에, C 언어에서 newline (NL) 이라는 문자의 추상화는 어렵지
않게 이루어질 수 있었습니다. 따라서, C Community 에서 만큼은 newline
이 외부 표현에 의존하지 않고 추상화된 EOL 의 행동을 기술하는 것으로 이
해해도 큰 문제 없습니다.

(IT 백두대간 C 언어, p.159)

>
> 입출력 함수는 크게 스트림을 대상으로 하는 것과 콘솔을 대상으로 하는
> 것으로 나눌 수 있고,

보다 정확히 말해 interactive device 를 염두에 두기는 했지만, 아래에서
말씀하셨듯이 C 언어의 입장에서 입출력은 모두 스트림으로만 이루어집니다.

[...]


>
> 실제 입출력이 수행되는 장치에서는 줄의 끝(end of line; EOL)이 서로 다른
> 방식으로 표현될 수 있고, 여러 문자로 표현될 수도 있습니다. 예컨대
>
> UNIX : EOL = LF * LF(line feed) = ASCII #10
> Macintosh : EOL = CR * CR(carriage return) = ASCII #13
> MS-DOS/Windows : EOL = CR + LF
>
> 이라고 합니다. 이 밖에도 다른 경우도 있을 수 있겠고요.

Macintosh 에 대해서는 조금 정정이 필요한 듯 합니다. 아시겠지만, OS X
에서는 커널에 중대한 변화가 있었기 때문에 다음과 같이 정리할 수 있습니
다.

Mac OS X 이전 : CR
Mac OS X : LF
AIX : NEL (EBCDIC)
CP/M : CR LF
Cygwin : CR LF (혹은 LF)
MS DOS & Windows : CR LF
OS/390 : NEL
Unix : LF
VMS : variable-length record
fixed-length record
CR LF
CR
LF

참고로 VMS 는 file 에 type 을 설정할 수 있으며, Cygwin 은 설치 과정에
의해 CR LF 와 LF 가 결정됩니다. EBCDIC 의 NEL 는 "NExt Line" 을 의미합
니다.

여기서 재미있는 것이 record-oriented filesystem 입니다. 이 때문에

#include <stdio.h>

int main(void)
{
puts("ABCD ");
return 0;
}

와 같은 간단한 프로그램이 표준을 엄격히 따르는 프로그램이 될 수 없습니
다. (IT 백두대간 C 언어, p.111)

>
> 하지만 C 프로그램이 텍스트 스트림을 통해서 입출력을 수행한다면 이러한
> 다양한 EOL 문자열은 모두 하나의 NL(new line) 문자 '\n'으로 변환되기
> 때문에 위와 같은 차이점을 일일이 신경쓸 필요가 없습니다. 즉 윈도우에서
> 파일에 CR, LF 두 문자가 있을 때 이를 fgetc()로 읽으면 하나의 NL 문자
> '\n'이 읽히고, 하나의 NL 문자 '\n'을 fputc()로 쓰면 파일에는 CR, LF
> 두 문자가 기록되는 것입니다. 따라서 C 프로그램에서는 줄의 끝은 무조건
> NL('\n')이라고만 생각하면 됩니다.
>
> (여기서 주의할 것은, LF 및 CR은 ASCII에 정의되어 있고 코드값도 얼마라고
> 정해져 있는 구체적인 문자인 반면, NL('\n')은 C 표준에 이름과 효과만으로
> 정의되어 있고 코드값도 얼마라고 정의되어 있지 않은 추상적인 문자라는
> 것입니다. 즉 이 두 가지는 서로 다른 차원에 살고 있는 문자들입니다.)

이를 뚜렷이 보이는 예로, 앞서 언급한 record-oriented filesystem 중 하
나인 fixed-size record filesystem 에는 아예 개행을 수행하는 물리적인
문자가 존재하지도 않습니다. 그럼에도 C 프로그램 안에서는 자유롬게 '\n'
문자를 사용하여 원하는 display semantic 을 얻을 수 있습니다. 재미있는
예를 한가지 들면, 한 줄 LCD 를 출력 장치로 두는 implementation 에서는
'\n' 이 일정 시간의 delay 를 일으키는 것으로 구현될 수도 있습니다.

사소한 지적입니다만, ISO 646 은 US-ASCII 와 동일한 codeset 이 아닙니
다. ISO 646 IRV 만이 US-ASCII 에 해당합니다 - 만약 ISO 646 이 US-ASCII
였다면 (C 표준이 ISO 646 에 기반하는한) 못생긴 trigraph 를 도입할 이유
가 없었을 것입니다.

그럼...


--
Jun, Woong (myco...@hanmail.net)
Dept. of Physics, Univ. of Seoul
Web : http://c-expert.uos.ac.kr

김승범

unread,
May 18, 2003, 5:36:55 AM5/18/03
to
Jun Woong wrote:
>
> "김승범" <musi...@bawi.org> wrote in message news:3EC5BAC0...@bawi.org...
> >
> > 입출력 함수는 크게 스트림을 대상으로 하는 것과 콘솔을 대상으로 하는
> > 것으로 나눌 수 있고,
>
> 보다 정확히 말해 interactive device 를 염두에 두기는 했지만, 아래에서
> 말씀하셨듯이 C 언어의 입장에서 입출력은 모두 스트림으로만 이루어집니다.

그렇다면 도스용 터보 C의 <conio.h>에 선언되어 있는 getch(), putch()
등의 같은 함수도 스트림 대상인가요? 이들의 설명을 읽어보면 콘솔(자판과
화면)을 대상으로 한다는 점은 명확한데, 이 또한 스트림 대상 입출력에
포함시킬 수 있는 개념인가요? 제 생각에는 이들 함수의 입출력 특성은
스트림 대상의 입출력 특성과는 구분되는 점이 있는 것 같거든요.
(색깔 등의 속성이 있는 점, EOF의 개념이 없는 점, C의 FILE 스트림으로
재지향을 시킬 수 없는 점 등이 당장 떠오르는 것들이네요.)

또한 보통 터미널 입출력 함수라고 부르는, 유닉스 계열의 curses
라이브러리에서 제공하는 getch(), addch() 등의 함수의 경우는 어떤가요?

>
> 여기서 재미있는 것이 record-oriented filesystem 입니다. 이 때문에
>
> #include <stdio.h>
>
> int main(void)
> {
> puts("ABCD ");
> return 0;
> }
>
> 와 같은 간단한 프로그램이 표준을 엄격히 따르는 프로그램이 될 수 없습니
> 다. (IT 백두대간 C 언어, p.111)

표준을 엄격히 따르는 프로그램이 될 수 없다는 것은,
간단히 말해서 잘못된 프로그램이라는 뜻인가요?

> >
> > 같은 코드값에 대해 ISO 646(=US-ASCII)에서는 슬래시('/')를 뒤집어 놓은
>
> 사소한 지적입니다만, ISO 646 은 US-ASCII 와 동일한 codeset 이 아닙니
> 다. ISO 646 IRV 만이 US-ASCII 에 해당합니다 - 만약 ISO 646 이 US-ASCII
> 였다면 (C 표준이 ISO 646 에 기반하는한) 못생긴 trigraph 를 도입할 이유
> 가 없었을 것입니다.

그렇군요. 지적해 주셔서 고맙습니다.

--
김승범

Jun Woong

unread,
May 18, 2003, 7:19:15 AM5/18/03
to
"김승범" <musi...@bawi.org> wrote in message news:3EC75437...@bawi.org...

> Jun Woong wrote:
> >
> > "김승범" <musi...@bawi.org> wrote in message news:3EC5BAC0...@bawi.org...
> > >
> > > 입출력 함수는 크게 스트림을 대상으로 하는 것과 콘솔을 대상으로 하는
> > > 것으로 나눌 수 있고,
> >
> > 보다 정확히 말해 interactive device 를 염두에 두기는 했지만, 아래에서
> > 말씀하셨듯이 C 언어의 입장에서 입출력은 모두 스트림으로만 이루어집니다.
>
> 그렇다면 도스용 터보 C의 <conio.h>에 선언되어 있는 getch(), putch()
> 등의 같은 함수도 스트림 대상인가요?

"C 언어의 입장에서" 는 "C 표준의 관점에서는" 임을 강조하기 위해 사용한
표현입니다. 보다 정확한 의도는 그 윗 부분에 있습니다:

"getch() 함수가 애초에 확장이므로 표준의 이와 같은 개념이 그대로 적용
된다고도, 또 표준 IO 함수에 주어지는 제한이 그대로 적용된다고도 단언
할 수 없습니다만..."

즉, C 표준이 기술하는 모든 I/O 함수는 (여러 부분에서 interactive
device 를 고려하고 있지만) 분명 모두 (C 언어에서 사용하는 개념의)
stream 에 이루어지는 것이라는 뜻일 뿐입니다.

모든 I/O 함수를 고려할 때 이를 콘솔과 (C 언어의) stream 으로 구분할 수
있는 것은 아닙니다. 예를 들어, 파일 입출력을 위한 low-level I/O 함수는
stream 도 콘솔도 아닌 file 에 직접 이루어 지는 것입니다.

제가 stream 에 "C 언어에서 사용하는 개념의" 라는 수식을 반복하여 붙인
이유는 "stream" 이라는 용어 자체가 문맥에 따라 다른 의미로 쓰일 수 있
기에 C 표준에 의해 정의된 의미임을 강조하기 위해서 입니다.

> 이들의 설명을 읽어보면 콘솔(자판과
> 화면)을 대상으로 한다는 점은 명확한데, 이 또한 스트림 대상 입출력에
> 포함시킬 수 있는 개념인가요?

그렇지는 않습니다.

> 제 생각에는 이들 함수의 입출력 특성은
> 스트림 대상의 입출력 특성과는 구분되는 점이 있는 것 같거든요.

맞게 해석하셨습니다.

> (색깔 등의 속성이 있는 점, EOF의 개념이 없는 점, C의 FILE 스트림으로
> 재지향을 시킬 수 없는 점 등이 당장 떠오르는 것들이네요.)
>
> 또한 보통 터미널 입출력 함수라고 부르는, 유닉스 계열의 curses
> 라이브러리에서 제공하는 getch(), addch() 등의 함수의 경우는 어떤가요?

stream 에 적용되는 입출력이 아닙니다.

> >
> > 여기서 재미있는 것이 record-oriented filesystem 입니다. 이 때문에
> >
> > #include <stdio.h>
> >
> > int main(void)
> > {
> > puts("ABCD ");
> > return 0;
> > }
> >
> > 와 같은 간단한 프로그램이 표준을 엄격히 따르는 프로그램이 될 수 없습니
> > 다. (IT 백두대간 C 언어, p.111)
>
> 표준을 엄격히 따르는 프로그램이 될 수 없다는 것은,
> 간단히 말해서 잘못된 프로그램이라는 뜻인가요?

말 그대로 strictly conforming program 이 아니라는 뜻입니다 - 제 기억이
맞다면 "잘못된" 프로그램 까지는 아니며, implementation-defined 행동에
의존하기에 "이식성을 갖지 않는" 프로그램입니다.

0 new messages