나의 언어 편력기

from 로그/전공 2010/08/05 13:44
http://langdev.net/post/141 이곳을 보고 여러가지가 생각나서 적어본다.

* 1993 : GW-BASIC

 국민학교 다닐 때의 일이라, 학교에서 운영하던 방과후 컴퓨터 교실에서 배운 것이 먼저였는지 우리집에 컴퓨터를 구입하고 설치하는 것을 도와준 외삼촌이 알려주었는지 기억이 확실치 않다. 컴퓨터가 단순히 게임하고 타자쳐서 글쓰는 기계가 아니고 내가 시킨 일을 수행하기도 한다는 것을 가르쳐 준 언어.
 루비 튜토리얼에서도 한번 언급한 적 있지만, 함수도 없고, 사용자 정의 데이터타입도 없고, 변수 스코프도 없는, 구조적 측면에서는 정말 초보적인 언어다. 그러나 복잡한 개념을 가르칠 필요 없이 바로 눈에 보이는 결과가 나온다는 점에서 교육용 언어라는 애초의 목적에는 충실한 언어였다.
 95년 무렵부터 엄마를 졸라 사설 컴퓨터 학원에 다녔는데, 이곳에서 QuickBASIC을 구할 수 있었다. QuickBASIC은 GW-BASIC의 상당히 업그레이드된 버전이었다. 함수와 C 스타일의 typedef를 제공했고, 인터프리터 환경에서 개발한 후 EXE 파일로 컴파일할 수도 있었다. 무엇보다 간단한 에디터와 디버거를 통해 IDE와 유사한 환경을 제공했다. 예제 코드도 상당히 많이 들어 있었기 때문에, 프로그래밍의 기본을 QuickBASIC으로부터 다 배웠다 해도 과언이 아니다.

* 1996 : C

 위에 언급한 사설 컴퓨터 학원에서 turbo C 컴파일러를 통해 C를 배우게 되었는데, 대단한 언어라고 들었던 C가 어렵기만 하고 별로 재밌지 않아서 실망했던 기억이 있다. 명령어만 입력하면 삑삑 소리도 나고 원하는 위치에 글자도 뿌릴 수 있었던 GW-BASIC과 달리 C는 그 자체로 할 수 있는 일이 별로 없었다. 결국 QuickBASIC에 더 많은 시간을 투자했던 것으로 기억한다.
 애초에 시스템 프로그래밍 언어를 지향했던 C로서는 나의 악평(?)이 억울했겠지만, 당시 좀더 강력한 라이브러리를 자랑하던 borland나 watcom의 컴파일러는 나로서는 쉽게 구할 방법이 없었다. (turbo C 역시 borland사의 제품인 걸로 알고 있는데 어떻게 구했는지는 기억이 나지 않는다. 아마 불법복제였던 듯 싶다.)
 1999년 무렵에 gcc를 도스용으로 포팅한 djgpp 컴파일러를 통해 다시 C를 만나게 되었을 때 드디어 C의 매력에 빠지게 되었다. djgpp는 일단 공짜로 쉽게 구할 수 있었고(!) gnu 진영의 다양한 라이브러리를 쉽게 설치할 수 있었다. 이전까지는 게임 불법 다운로드(...)에나 사용하던 PC 통신에서 프로그래밍 관련 정보를 얻을 수 있다는 걸 알게 된 것도 이 무렵이었는데, 여기서 유전 알고리즘에 대한 간략한 소개를 보고 직접 prisoner's dilemma 문제를 코딩해 보기도 했는데 결과는 중구난방이었다. 지금 생각해보면 CPU가 구린 것을 나름 보완한다고 진화압력과 돌연변이 확률을 너무 크게 잡았기 때문이 아니었나 싶다.

* 2000 : C++

 djgpp는 C 컴파일러이기도 했지만 C++ 컴파일러이기도 했기 때문에 자연스럽게 C++를 접할 수 있었다. C++는 참 이름을 잘 지은 것이, 사실 C와 큰 관련이 없는 언어지만 이름 때문에 C의 후계자가 C++라고 아주 당연하다는 듯이 생각하고 있었던 것 같다.
 C++는 수많은 키워드와 에러나기 쉬운 메모리 관리 시스템 때문에 참 어려웠는데, 나는 "진짜" 프로그래밍 언어는 어려운 것이 당연하지 하면서 열심히 배웠다. 지금은 단순히 C++의 문법이 지저분한 것 뿐이라고 생각한다. 게다가 당시에는 C++ == MFC 인 것마냥 대부분의 책이 MFC만을 다뤘기 때문에, C++의 진짜 힘인 template의 존재를 알지 못했다. MFC나 좀 건드려 보다가 말았던 걸로 기억한다. 매크로로 떡칠된 MFC의 라이브러리 디자인은 지금도 좋아하지 않는다.
 나중에 대학교에 들어와서 C++를 다시 돌아보게 되는 데는 Effective C++와 더 나중에 만난 Modern C++ design 의 도움이 컸다. 특히 Modern C++ design은 C++의 강력함과 한계를 동시에 알게 해 주는 책이다. 적극 추천하는 바이다.

* 2003 : java

 대학교에 들어와서 전공이 정해진 후 프로그래밍의 기초 시간에 Java를 처음 배웠던 것 같다. C++과 열심히 씨름했던 덕분에 Java는 참 쉽게 배울 수 있었다. template을 제외하면 C++의 핵심적인 기능은 대부분 Java에도 있었고, 덤으로 좀더 단순한 문법과 풍부한 기본 라이브러리를 자랑한다. (Java에도 훗날 template이 추가되었다.)
 그러나 개인적으로는 java가 차지하고 있는 위치가 애매하달까... CPU 성능을 극단적으로 요구하는 프로젝트는 C가 더 나은 경우가 많고, 병렬 프로그래밍은 haskell이 훨씬 쉽고, 보다 generic한 프로그래밍에는 상황에 따라 파이썬이나 루비를 사용하기 때문에 요즘은 java는 그다지 좋아하지 않는다.
 특히 자바 커뮤니티는 다른 언어로 된 라이브러리 갖다 쓰는 것을 굉장히 싫어하고 모든 것을 자바 언어 내에서 해결하고 싶어하는 특징이 있는데, 나에게는 별로 맞지 않는 것 같다.

* 2004 : nML

 이 언어는 모르는 사람들이 많을 텐데, 서울대학교 이광근 교수님이 Standard ML과 OCaml의 디자인을 합쳐 만든 ML의 방언이다. 프로그래밍 언어 시간에 nML을 처음 만났을 때의 충격을 아직도 잊을 수 없다. 아마 함수형 언어를 배운 사람들은 대부분 함수형 언어와 처음 만나는 순간을 충격적으로 기억하고 있을 게다.
 함수형 언어의 심플한 아름다움은 아마 접해본 사람은 다들 알고 있을 것이고 접해보지 않은 사람에게는 말로 전달해줄 능력이 없다. 두려워하지 말고 만나보라고 할 수밖에. 프로그래밍을 바라보는 눈이 바뀔 것이다.
 하지만 지금은 nML을 쓰지 않는다. 함수형 언어를 쓰고 싶은 프로젝트를 만나면 그냥 Haskell을 쓴다...

* 2004 : PHP

 웹 프로젝트에 잠시 사용해 봤다. 끝... 이 아니고...
 네트워크 프로그래밍 시간에 처음 써봤고, 이후에도 웹 개발할 일이 있을 때 한두번 더 써보기도 했지만, 지금은 웹 개발은 전부 루비로 하고 있다.

* 2005 : python

 파이썬의 강력함은 이전부터 익히 들어 왔지만, 실제로 다뤄본 것은 4학년때 잠깐, 그리고 대학원에 들어가고 나서의 일이었다. 대학원에서는 주로 numpy와 scipy를 통해 수치해석을 많이 했고, 요즘 들어서는 twisted로 네트워크를 많이 다루고 있다.
 워낙 대세가 되어 개발자라면 써보지 않은 사람이 없을 것이다. 나 역시 혼자 작업할 때는 루비를 선호하지만 국내 개발자 가운데서도 루비 쓰는 사람은 별로 없어도 파이썬 안써본 사람은 거의 없기 때문에 누군가와 함께 작업할 때는 대부분 파이썬을 쓰게 된다.

* 2006 : matlab

대학원에서 처음 접하게 된 언어. 수치해석과 그래프 그리기의 최강자. 그러나 과제 때 몇번 써보고 이후에 비슷한 과제가 있을 때는 그냥 numpy로 대체해 버렸다.

* 2007 : ruby

 실용적인 프로그래밍의 진정한 의미를 가르쳐준 언어이자, 프로그래밍 언어의 문법이 심플하지 않아도 아름다울 수 있다는 것을 가르쳐준 언어. 루비의 특징은 이 블로그에서 몇번 소개하였으므로 루비 태그를 참조하시면 되겠다.
 루비는 언어 자체도 독특하지만 커뮤니티 역시 참 독특하다.
  * 테스트 주도 개발을 거의 맹신이라고 할만큼 철저히 지킨다. 테스트 주도 개발은 java 진영에서 먼저 보편화되었지만, 요즘은 루비의 훌륭한 테스트 도구들이 java/python 진영으로 역수출되는 추세다.
  * Mac 사용자의 비중이 다른 커뮤니티에 비해 높다. 사용자 친화를 중시하는 애플 진영의 특성과 프로그래머 친화를 중시하는 루비의 특성이 잘 맞기 때문인 것 같다. 덕분에 루비의 Mac OS 지원도 상당히 훌륭하다.
  * 웹 개발자가 많다. 이것은 물론 Ruby on Rails 라는 걸출한 프레임워크 덕분인데, 이 때문에 다른 분야 라이브러리들의 발전은 느린 편이다. 루비 커뮤니티에서 가장 아쉬운 점이다.

* 2008 : haskell

 프로그래밍 언어의 진화의 한 정점에 서 있는 언어. 세상에서 가장 정교한 프로그래밍 언어를 꼽으라면 나는 주저없이 haskell을 꼽을 것이다.
 side-effect를 허용하지 않는 순수 함수형 언어로, side-effect 없이 I/O를 구현하기 위해 monad라는 독특한 개념을 이용한다. 순수 함수형 언어라는 점을 제외하면 nML과 유사한 문법을 갖고 있어서 쉽게 입문할 수 있었는데, 배우면 배울수록 새로운 개념이 끊임없이 등장하는, 굉장히 깊은 언어이다. 게다가 학자들이 좋아하는 (...) 언어다 보니 새로운 프로그래밍 패러다임의 주된 실험장이기도 하다.
 실용적인 측면에서 haskell의 가장 큰 특징은 persistent data일 것이다. nML이나 LISP 등 대부분의 값 중심 (함수형 언어의 다른 별명) 언어들의 특징이기도 한데, 한번 계산된 값은 절대 변경되지 않는다는 것이다. 예를 들어 list에 새로운 값을 추가하거나, hashmap에 새로운 key/value를 추가해도 원래 값은 변하지 않고 그로부터 계산된 새로운 값이 반환된다. 또한 같은 함수에 같은 값을 넣으면 항상 같은 동작을 한다는 것이 100% 보장되기 때문에 일단 컴파일된 코드는 높은 확률로 의도대로 동작한다는 것을 보장하는 훌륭한 특성을 갖고 있다.
 다만 함수형 언어의 생소함 외에도 monad라는 수학적인 개념을 광범위하게 다루고 있기 때문에 배우기 어려운 언어인 것은 사실이다. haskell을 공부하고 싶은 사람에게는 공식 홈페이지 www.haskell.org 와, haskell의 실용적인 측면을 많이 다루고 있는 Real World Haskell을 추천한다.

* 2010 : actionscript

 flash 개발을 위한 언어. javascript 방언이다. 회사에서 쓸 데가 있어 배우긴 했는데 언어적으로 참 지저분하다 -_- flash까지 덩달아 싫어지게 만드는 마술같은 언어.

* 2010 : lua

 와우 애드온 고칠때 조금 끄적여본 수준. 재미있어 보이긴 하는데 많이 들여다보지는 않았음.

 이렇게 써놓고 보니 대학교에 입학한 이후로는 나도 모르는 사이에 매년 새 언어 배우기 원칙을 실행하고 있었다... 2009년에는 딱히 새 언어를 배우지 않았다는 것이 갑자기 아쉬워진다.

* 그 외에 요즘 기대하고 있는 언어들

 clojure : 요즘 루비 커뮤니티에서 주목받고 있는 LISP 방언이다. LISP가 등장한지 50년이 넘었지만 여전히 코드를 그 자체로 데이터로 다루는 LISP만의 특징은 다른 언어들은 흉내만 낼 뿐 완전히 구현하지 못하고 있다. clojure는 현대 언어들의 기능 (dynamic inheritance, hashmap, STM 등등) 으로 재무장한 LISP라고 할 수 있는데, 자바 가상 머신 위에서 동작하기 때문에 자바의 수많은 라이브러리를 바로 갖다 쓸 수 있다는 장점이 있다. 다만 등장한지 얼마 되지 않아서 API가 확립되지 않은 것이 단점이라 하겠다.

 go : 작년에 구글에서 공개한 언어. 디자이너 가운데 무려 켄 톰슨[각주:1]과 롭 파이크[각주:2]가 포함되어 있다. 역시 구글이랄까 I/O 함수와 강력한 병렬처리에 집중하는 점이 돋보인다. 이번 프로젝트 끝나면 회사에서 한번 스터디해볼 계획이다.
  1. B 언어(C 언어의 전신), Unix, UTF-8을 개발한 업계의 전설 [본문으로]
  2. 역시 Unix의 개발자. 또하나의 전설 [본문으로]
http://www.youtube.com/user/TheCatsters

평균 5분~10분 사이 동영상이 77개니까 약 9시간, 대학 강의로 치면 반개 학기 분량의 강의다. 관심이 있긴 하지만 이거 끝까지 들을 수 있나 ㄷㄷㄷ
SSH 터널링이란 - 특정한 포트로 들어오는 IP 패킷을 SSH 접속을 이용해 다른 컴퓨터로 중계해 주는 프로토콜을 가리킵니다. SSH 터널링을 이용하면 방화벽이나 사설망 안에 물려 있어 외부에서 접속이 불가능한 PC에 접속하는 것이 가능합니다.

다음과 같은 시나리오를 예로 들어 보겠습니다.

직장의 사설망 내부에 작업용으로 사용하는 리눅스 PC가 있습니다. 외부에 있는 윈도우 컴퓨터에서 putty로 작업용 PC에 접속하고 싶습니다. 이때 사설망 외부에 SSH 서버가 있다면 터널링을 이용해 작업용 리눅스에 접속할 수 있습니다.

세 대의 컴퓨터가 각각 다음과 같은 이름을 가졌다고 가정합시다.

office_linux_pc : 사설망 내부에서 사용하는 linux pc. 사설 IP는 192.168.0.101 이라고 합시다.
ssh_server : 사설망 외부의 SSH 서버. IP는 147.46.101.102 이고, 계정 이름은 kanie라고 합시다. (도메인 이름이 있다면 ip 대신 도메인 이름을 사용해도 됩니다.)
home_windows_pc : 외부에 있는 윈도우 컴퓨터. 인터넷에 접속만 가능하다면 IP는 무관합니다.

필요한 프로그램은 다음과 같습니다.
office_linux_pc : 이 컴퓨터에 SSH로 접속하고 싶은 것이니만큼 SSH 서버가 필요하겠죠. HTTP로 접속하고 싶다면 역시 HTTP 서버가 필요합니다. 서버가 설치되어 있다면 루트 권한이 필요하지는 않습니다.
ssh_server : SSH 서버가 필요합니다. root 권한을 가질 필요는 없습니다.
home_windows_pc : 윈도우용 SSH 클라이언트인 putty를 설치합시다. putty와 같이 따라오는 윈도우 커맨드라인용 ssh 클라이언트인 plink도 필요합니다.

office_linux_pc에서 ssh_server로 SSH 링크를 엽니다. 147.46.101.102 서버의 3030번 포트로 들어오는 모든 접속을 localhost(이 경우 office_linux_pc가 되겠죠)의 22번 포트로 우회시키는 명령입니다. 22번 대신 80번 포트를 넣으면 외부에서 http 서버에 접속할 수 있습니다.

ssh -R 3030:localhost:22 kanie@147.46.101.102

패스워드를 물어보면 입력하고 접속하면 됩니다.

이제 office_linux_pc를 켜놓고 집으로 갑시다.

home_windows_pc에서 cmd로 콘솔을 열어 다음과 같이 입력합시다. 이번엔 localhost(home_windows_pc)의 4040번 포트로 들어오는 모든 접속을 147.46.101.102 서버의 3030번 포트로 우회시키는 명령입니다.

plink -L 4040:localhost:3030 kanie@147.46.101.102

이제 putty로 localhost:4040 포트에 접속합시다.



office_linux_pc의 ID와 password를 입력하고 접속하면 됩니다.

요즘 (2000년대 후반) 나오는 리눅스 배포판들은 패키지 관리를 깔끔하게 해주기 때문에 원하는 프로그램을 마우스 클릭 한두번으로 설치하고 사용할 수 있지만, 그게 여의치 않은 경우가 있죠. 예를 들면 원하는 프로그램이 패키지 목록에 없을 때라던가, 아니면 관리자 권한이 없어 프로그램을 마음대로 설치할 수 없는 경우요. 그럴 때는 소스를 직접 다운받아서 설치하고, 제거해야 합니다.

리눅스 사용자들은 아마 다 알고 계시겠지만, 그래도 저같은 리눅스 초보에게는 tar.gz로 묶인 소스코드 뭉치를 던져주고 알아서 설치를 하라고 하면 머리가 아파오지요. 우리 모르는 사람들끼리 서로서로 설치/제거법을 알아보아요.


설치 준비하기

예를 들어 설명해봅시다. 저는 요즘 하는 일 때문에 ImageMagick이라는 라이브러리가 필요합니다. 학교에서 사용하는 서버는 우분투 리눅스 5.10인데, 우분투의 친절한 패키지 관리자를 통해 ImageMagick 을 설치할 수는 있긴 하지만... 버전이 6.2.xx 네요. 제게 필요한 버전은 6.3 이상이므로, 6.3 버전 소스 코드를 다운받아 직접 설치하기로 했습니다.

만약 우분투를 쓰고 계시다면, 그리고 소스 코드 컴파일을 한번도 해본 적이 없다면, (혹은 컴파일이란 게 뭔지 모르신다면) 컴파일과 설치를 위한 기본 도구들을 먼저 설치해야 합니다. 설치는 간단합니다. 시냅틱 패키지 관리자나, sudo aptitude를 이용해서 build-essential 패키지를 설치하세요.

대부분의 다른 리눅스 배포판들은 gcc / make / ld 등의 도구들이 다 깔려 있습니다. 다음으로 진행합시다.


소스 코드 다운받기

구글로 검색해서 ImageMagick의 홈페이지를 찾았습니다. 다운로드 페이지를 잘 읽어보고 원하는 소스 코드를 다운받습니다. 저의 경우 주소는 ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz 이렇게 되네요.

웹 브라우저로 검색해서 다운받는다면 다운받는 것은 쉽습니다. 그러나 리눅스 GUI에 직접 접근할 수 없고, 커맨드라인만 사용할 수 있는 환경이라면, wget을 사용하면 됩니다. wget은 대부분의 리눅스 배포판에 기본으로 깔려 있으므로, wget [웹 주소] 이렇게만 치면 됩니다.

wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz

소스 코드를 다운받았습니다. 압축파일 이름은 ImageMagick.tar.gz 네요. 이제 다운받은 압축파일을 풀어봅시다.

리눅스 환경에서 대부분의 압축 파일은 확장자가 tar.gz로 되어 있습니다. 만약 GUI를 사용할 수 있는 환경이라면 그냥 압축파일 관리자를 이용해 새 디렉토리에 압축을 푸시고, 아니라면 tar를 이용해 압축을 풀어 봅시다. tar -xzvf [파일 이름] 이라고 치면 됩니다.

tar -xzvf ImageMagick.tar.gz


설치 문서 읽기

여기서부터가 까다롭습니다. 소스 패키지 설치는 GUI로는 진행할 수 없기 때문에, 먼저 리눅스 터미널을 열어야 합니다. 열었으면, 압축을 푼 디렉토리로 가봅시다. ImageMagick-6.3.9 라는 디렉토리가 생겼네요.

cd ImageMagick-6.3.9

일반적으로 소스 패키지 설치는 configure / make / make install 의 3단계로 이루어집니다. configure는 설치 전에 여러가지 옵션을 지정해주고 컴파일 환경을 검사하는 단계입니다. configure 옵션은 프로그램마다 조금씩 다르므로, 설치 전에 먼저 README나 INSTALL 같은 설치문서를 읽어보는 것을 추천합니다. (문서가 주로 영어로 되어 있다는 것은 참 슬픈 일입니다.) 여기서 설치 옵션 부분을 읽어보고 나에게 필요한 옵션이 있다면 적어둡니다.


configure

configure는 내게 필요한 도구가 다 있는지, 라이브러리는 다 있는지 같은 것들을 체크해주고 빌드 환경을 만들어주는 스크립트입니다.

설치할 때 옵션을 주지 않으면 기본으로 /usr/local/bin 이나 /usr/local/lib 밑에 설치하는데, 이 디렉토리들은 관리자 권한이 없이는 접근할 수 없습니다. 이 경우에는 --prefix 옵션을 주어 설치 디렉토리를 바꿔야 합니다. 저는 저의 홈 디렉토리 밑에 imagemagick이라는 디렉토리를 만들어 그 곳에 설치하기로 했습니다. (이 경우 홈 디렉토리를 ~ 기호로 축약하는 것은 보통 에러를 일으킵니다. 루트 디렉토리부터 절대경로를 다 써주어야 합니다.)

./configure --prefix=/home/kanie/imagemagick

그 외 다른 옵션들도 넣어 보았습니다.

./configure --prefix=/home/kanie/imagemagick --disable-static --with-modules --without-perl --with-x=no

이렇게 하면 이제 컴파일 준비가 완료됩니다.

configure 단계에서 에러를 내며 멈출 경우

보통은 빌더 환경이 잘 갖추어져 있지 않다는 것을 의미합니다. 필요한 프로그램이나 라이브러리가 없는 경우가 대부분이므로, 빌드 문서를 잘 읽어보시고 필요한 프로그램이나 라이브러리를 설치해 주세요.

configure 옵션을 잘못 주어서 다시 시작하고 싶다면

make distclean이라고 치면 configure 설정을 모두 제거해줍니다. 그리고 configure 부터 다시 시작하시면 됩니다.

make distclean


make / make install

make는 미리 정해진 스크립트를 따라 소스 코드를 컴파일해주는 도구입니다. configure를 마쳤다면 make를 쳐서 컴파일합니다.

make

make가 실패하는 경우는 보통 컴파일 에러입니다. 이때는 컴파일 에러를 해결한 후 처음부터 다시 컴파일하는 것을 추천합니다. make clean 하면 컴파일이 취소되고, make를 치면 다시 컴파일할 수 있습니다.

make clean

컴파일이 완료되면 make install 을 치면 설치가 완료됩니다.

make install

설치한 후에 압축파일을 풀었던 디렉토리는 지우지 않는 것을 추천합니다. 나중에 설치 제거할 때 필요하니까요.


설치 제거하기

설치 제거를 하려면 make를 했던 디렉토리로 돌아와 다음과 같이 치면 됩니다.

make uninstall

언제나처럼, 스스로를 이해시켜서 나중에 써먹기 위해 쓴 글입니다. (기계과나 전기과에서 배우는 내용인 듯 한데... 논문 읽다보면 종종 튀어나와서...) 사용된 근거의 정확성이나 이론적 무결성은 보장하지 않습니다. 이 분야에 대해 정말 써먹을 수 있는 지식이 필요하신 분은 신뢰할만한 textbook을 참고하세요.

제어이론이 뭔가요?

제어이론은, 굉장히 여러가지 요소를 가진 예측하기 힘든 시스템을(미쿡말로는 dynamic system이라고 합니다.) 1. 의도한 대로, 2. 안정적으로 움직이게 하기 위한 공학이론입니다.

단도직입적으로, 운전자가 직접 운전하지 않고 컴퓨터가 알아서 운전하는 자동차가 있다고 생각해 봅시다. 운전자는 직접 핸들을 잡고 엑셀을 밟아 자동차를 운전하는 것이 아니라, 사용자가 원하는 속도를 입력하면 그 속도를 유지하며 달리게 됩니다. 운전자가 자동차에게 "시속 60km로 달려라" 하고 명령을 내렸다고 합시다. 자동차의 속력에는 많은 요소가 작용하지만, 엔진의 스로틀(엔진에 연료를 분사하는 비율을 조절하는 밸브 정도로 이해하시면 됩니다)이 가장 큰 역할을 할 겁니다. 예를 들어 스로틀이 연료를 초당 50mg의 비율로 분사하면 자동차의 속도가 60km/h가 되는 걸로 실험실에서 대충 계산이 나왔다고 합시다.

그러면 자동차를 원하는 속도로 달리게 하고 싶을 때 생각할 수 있는 가장 간단한 방법은, 운전자가 원하는 속도 60km/h를 입력하면(외부입력) 사전에 계산된 어떤 방정식을 통해서(컨트롤러) 그에 맞는 스로틀의 비율인 초당 50mg으로 자동차를 제어(출력)하는 겁니다. 이렇게 외부입력만을 받는 가장 간단한 시스템을 feed-forward controller라고 합니다.

그러면 그냥 스로틀을 초당 50mg으로 고정시키면 자동차의 속력이 정확히 60km/h가 나오느냐... 그건 아닙니다. 오르막길에서는 엔진의 힘이 같더라도 속도가 느려질 것이고, 내리막길에서는 더 빨라질 거구요, 비포장도로에서는 또 느려질 거고, 고속도로에서는 좀더 빨라질 겁니다. 그 밖에도 공기저항이라든지, 도로가 비에 젖어서 마찰력이 적다던지 하는 수많은 상황이 발생할 수 있는데, feed-forward controller는 이런 종류의 외부 상황 변화에 대해 반응할 방법이 전혀 없다는 것이 단점이죠.

그러면 좀더 똘똘한 컨트롤러를 생각해봅시다. 사용자가 원하는 속도 60km/h를 입력하면, 스로틀을 초당 50mg으로 일단 맞춰놓고 달려봅니다. 그런데 오르막길에다 도로 상황도 별로 좋지 않아서 속도가 40km/h 정도밖에 안 나오네요. 그러면 스로틀을 조금씩 더 열어 더 빠른 속도를 냅니다. 그러면 점점 속도가 올라 60km/h가 되겠죠. 그러면 그 상태로 스로틀을 유지하는 거죠. 어 그런데 길이 내리막으로 바뀌었군요. 속도가 빨라집니다. 그러면 더 빨라진 속도를 입력으로 받은 컨트롤러는 다시 서서히 스로틀을 닫아 속도를 줄입니다. 그러면 다시 60km/h에서 속도가 안정되겠죠.

이렇게 자동차의 속도(출력)를 다시 컨트롤러(복잡한 톱니바퀴로 스로틀을 제어하는 기계일 수도 있고, 아니면 자동차에 탑재된 조그만 컴퓨터일 수도 있겠죠.)에게 입력으로 주어 (피드백, 우리말로는 되먹임) 컨트롤러가 스로틀(출력)을 더 늘리거나 줄일 수 있도록 한다면, 자동차의 속도를 외부 환경에 큰 영향을 받지 않도록 안정적으로 제어할 수 있습니다. 이런 간단한 되먹임 시스템을 피드백 컨트롤러라고 합니다.

피드백 컨트롤은 사실 모든 생물이 자기 자신을 제어할 때 사용하는 테크닉이기도 하고, 엔지니어들이 오래 전부터 사용해온 테크닉이기도 합니다. 그럼 제어이론(control theory)이라는 거창한 이름이 붙은 이유는 뭐냐... 이 피드백 시스템을 수학적으로 잘 모델링하려는 거죠. 피드백 시스템을 보다 안정적으로 유지하며, 갑작스런 외부 요인으로 시스템이 요동을 쳐도 다시 원래 상태를 회복할 수 있도록 (영어로는 robust하다고 합니다.) 하는 안전한 컨트롤러를 설계하는 것이 제어이론의 목표입니다.

PID 컨트롤러

피드백 시스템중에 (비교적) 이론적으로 간단하고 실제로 제일 많이 응용되는 것은 PID 컨트롤러라고 합니다. 이 PID 컨트롤러에 초점을 맞춰 설명을 해보죠.

PID 컨트롤러에게는 입력(자동차 예제로 설명하면 사용자가 원하는 속도 60km/h) r(t)이 주어집니다. 그냥 고정된 값 r이 아니라 r(t)인 이유는 이 값이 시간 t에 따라 변할 수 있기 때문이죠. 이 값을 입력으로 받은 컨트롤러는 시스템을 제어(이 경우 자동차 스로틀을 바꾸겠죠)하고, 거기에 따라서 시스템의 전체 출력(자동차의 속도) y(t)가 변할 겁니다. 이 시스템을 완벽하게 컨트롤한다면 r(t)와 y(t)는 같은 값이 되겠지만, 실제로 그렇지는 않을 거고 약간의 차이가 존재하겠죠. 이 차이를 e(t) = r(t) - y(t) 라고 합시다.

PID 컨트롤러는 이 e(t) 값에 어떤 상수를 곱하고(Proportional : 비율이라는 뜻이죠) 적분(Integral)을 하고 미분(Derivative)을 한 값을 컨트롤러에게 다시 되먹여서 시스템을 제어한다고 해서 PID 컨트롤러라 부릅니다. 만약에 여기서 적분값 I를 쓰지 않는다면 PD 컨트롤러, D를 쓰지 않는다면 PI 컨트롤러, 그냥 결과값에 상수만 곱해서 되먹인다면 P 컨트롤러가 됩니다.

수식으로 쓰면,
latexP.png
latexI.png
latexD.png
이런 식이 됩니다. 여기서 Kp, Ki, Kd는 각각 적당한 상수가 되겠죠.

이때 컨트롤러는 구동장치(actuator : 시스템을 실제로 작동시키는 장치. 우리의 예제에서는 스로틀이 되겠죠)를 u만큼 움직여서 시스템을 조절하는데, PID 컨트롤러의 경우 이 u 값이 u = P + I + D 가 되는 것이죠.

P, I, D의 계수 Kp와 Ki, Kd는 각각 시스템의 안정성에 일정한 영향을 미칩니다.

Change of response for varying Kp

Kp는 이 경우 시스템이 오차 e에 얼마나 빠른 속도로 반응하는가를 결정합니다. 자동차 예제에서, 극단적으로 Kp가 0이라면 컨트롤러는 전혀 시스템에 반응하지 않고, 따라서 자동차는 전진하지 않겠죠. 반대로 Kp가 매우 크다면? 정지상태에서 사용자가 60km/h라는 값을 입력했을 때 급가속하여 순식간에 60km/h에 가까워질 겁니다. 그러나 안정적으로 60km/h를 유지하지 못하고 상하로 요동이 심해집니다.

Change of response for varying Ki

Ki는 안정상태에 들어선 시스템이 미세한 오차를 얼마나 빨리 제거하는가를 결정합니다. Ki가 0인 시스템은 안정 상태에서도 정확히 입력값에 다가서지 않고 지속해서 요동칩니다. 그러나 반대로 Ki가 너무 크면 Kp의 경우와 마찬가지로 시스템이 불안정해지죠

Change of response for varying Kd

Kd는 시스템이 얼마나 빨리 안정상태에 들어서는가를 결정합니다. Kd가 큰 시스템은 금방 요동을 멈추고 안정 상태에 들어섭니다. 반면에 Kd가 너무 크면 입력값에 도달하는 속도가 느려지죠.

이런 시스템의 안정성에 대해 자세히 논하려면 라플라스 이론이라는 것을 알아야 하는데, 공학수학을 대충 배워서 -_- 라플라스 이론에 대해서는 자세히 모르는고로 이 부분은 스킵하겠습니다.

이게 어디에 도움이 되나요?

어려워 보이지만, 사실 PID 컨트롤러는 의외로 주변 곳곳에서 발견됩니다. 위에서 예로 든 자동차의 속도조절장치는 물론이고, 하드 디스크의 헤드 제어, 파워 서플라이의 전압 조절, 정교한 전자식 지진계 같은 곳에도 쓰입니다. 같은 이론을 스프링과 지렛대를 이용한 기계장치에까지 적용하면 포크레인 같은 대형 건설장비에 사용되는 제어 시스템도 일종의 PID 컨트롤러입니다.


ps. 재미는 없지만 지켜야 할 라이선스 문제 :

위 내용의 대부분은 영문 wikipedia를 적당히 편집한 결과입니다. 따라서 자동적으로 이 문서는 GFDL 라이선스를 따릅니다. 이 내용을 가져가서 재배포하실 때는 반드시 이 문서가 GFDL 라이선스를 따른다는 것을 명시하셔야 하며, 이 내용을 수정/변경하실 때는 그 결과물 또한 GFDL 라이선스를 따라야 합니다.

이 글은 스프링노트에서 작성되었습니다.

캠리브지 대학의 연결과구에 따르면, 단들어이 배되열어 있는 순서는 중하요지 않다고 한다.
첫째번와 마막지의 글자 위치가 정기확하만 하면, 나지머는 엉창망진이 되어도 문없제이 읽을 수 있다.
이것은 인간의 두뇌가 문자를 일일이 인하식지 않고 단어 전로체서 인하식기 때이문다.
이 문장은 정으상적로 적은 한어국를 파썬으이로 뒤어섞본 문이장다.

하나하나 읽으려고 하는 것보다 빨리 읽으면 왠지 스르륵 읽힌다...

파이썬 코드



p.s. 이건 실제로는 캠브리지 대학의 연구결과가 아니라고 합니다. 그래도 재미있는 코딩 연습이 되었군요. 결과물도 재미있고요.

image morphing 과제

from 로그/전공 2006/04/17 17:33

control point 대략 40개, biharmonic RBF interpolation.
control point를 많이 찍었더니 artifact는 보이지 않지만 중간 결과물이 몹시 뾰족뾰족함.
jpg로 저장해서 그런지 아니면 원본 이미지가 그래서인지 노이즈가 많음.
thin-plate로 하면 더 오래 걸릴까...

스도쿠

from 로그/전공 2005/06/08 12:25


스도쿠는 종이와 연필만 있으면 풀 수 있는 간단한 논리 퍼즐입니다. 80년대에 일본에서 유행했다가 잠잠해졌는데, 요즘들어 뒤늦게 영국에서 유행중이라는군요. 스도쿠는 數獨의 일본식 발음이라고 하네요.

이 퍼즐을 푸는 방법은 간단합니다.

3가지 규칙이 있습니다.

1. 가로줄에는 1부터 9까지의 숫자가 하나씩 들어간다.
2. 세로줄에는 1부터 9까지의 숫자가 하나씩 들어간다.
3. 9개의 3x3 사각형에는 1부터 9까지의 숫자가 하나씩 들어간다.

세 개의 규칙을 가지고 이쪽저쪽으로 끼워맞춰보고, 시행착오를 겪다 보면, 어느 칸에 어느 숫자가 들어가게 될지 짐작할 수 있습니다. 하나하나 채워서 81개의 칸을 다 채우면 완성.

시시하게 들릴지도 모르지만 굉장히 재미있어요. 시험기간은 제쳐두고 요즘 이 퍼즐에 말려 있습니다 oTL



그런데, 프로그래머라면 이 퍼즐을 갖고 놀다가 본능적으로 떠오르는 의문이 있을 겁니다. 이 퍼즐을 자동으로 풀어주는 프로그램을 만들 수 있지 않을까? 네. 자동화는 프로그래머의 본성인 겁니다 -_-

간단하고 쉽게 예상할 수 있는 알고리즘이 있습니다.
1. 모든 칸마다 들어갈 수 있는 후보 숫자들을 표시한다.
2. 후보 숫자가 하나뿐인 칸은 그 숫자로 채운다.
3. 가로줄, 세로줄, 혹은 3x3 사각형에 한 숫자가 들어갈 수 있는 자리가 하나밖에 없으면 그 칸을 채운다.

네. 간단한 퍼즐의 경우 위의 1, 2, 3을 반복하면 퍼즐을 풀 수 있습니다. 손으로 풀 때도 종이와 연필만 있으면 쉽게 문제를 풀 수 있는 방법이지요. 그러나 퍼즐이 좀더 어려워지면 위의 1, 2, 3만으로는 문제가 해결되지 않는 상황에 맞닥뜨리게 됩니다.

손으로 문제를 풀 때는, 여기서부터 복잡한 논리적 추론이 들어가게 됩니다. 논리적인 추론을 통해서 몇가지 후보들을 제거하다 보면 막혔던 게 풀리는 경우도 있고, 그것도 안되면 후보들 중에 하나를 그냥 찍어봐서 모순이 생길 때까지 밀고 나가보는 방법도 있습니다.

그러면 컴퓨터로 이 문제를 풀 수 있는 좀더 스마트한 알고리즘은 없는 걸까요?



안타깝게도, 없습니다. -_- 이 문제는 NP-Complete라는 사실이 증명되었거든요. 따라서 P=NP 문제가 증명되어 컴퓨터과학계가 통째로 열번쯤 뒤집히기 전에는 이 문제를 푸는 스마트한 알고리즘은 안 나옵니다. 그저 CPU의 성능을 믿고 열심히 백트래킹해보는 수밖에요. 다행히 81칸밖에?! 되지 않으니 해가 유일할 경우 합리적인 시간 내에 답이 나오긴 합니다.

이런 순수한 논리 퍼즐 가운데 많은 문제가 NP-Complete라는 사실이 알려져 있지요. 지뢰찾기를 해결하는 문제도 NP-Complete라고 해요. 그런 걸 보면, 실은 NP-Complete 문제는 인간은 비교적 쉽게 풀 수 있지만 컴퓨터는 절대 쉽게 풀 수 없는 문제들의 집합일지도? 하는 실없는 생각을 잠시 해보았습니다...;
요즘은 유니코드 문서를 사용하는 프로그램을 하나 짜고 있습니다. c 라이브러리만 가지고 유니코드를 사용하기 위해 공부하다 보니 다른 인코딩과 관련된 자료들도 보게 되는데, 완성형과 조합형만 알면 해결되던 도스 시절에 비해 정말 놀라울 정도로 복잡하고 지저분하군요. 한글은 참 효율적이고 심플하면서도 범용성이 높은 문자지만, 공학적인 견지에서는 디자인의 비일관성때문에 약간 골치아픈 문자라고 생각합니다. 아니면 다른 무식한 문자들과 함께 사용하려니 어려운 걸까요 -_-

1. KS 완성형(KSC5601, ISO2022-KR, euc-kr)

한글 코드와 관련된 그 모든 저주의 시작. 누가 어쩌자고 이런 절름발이를 국가 표준으로 정했는지 때려주고 싶을 정도죠. 아마 국제 표준인 ISO-2022에 맞추어 황급히 제작했을 것으로 추측합니다.
KSC5601은 KS 표준번호, ISO2022는 ISO 표준번호고, euc-kr은 유닉스에서 붙인 인코딩 scheme 이름입니다. KSC5601은 역슬래시 기호 대신 원화 기호를 쓴다는 점에서 아주 약간 다릅니다. 윈도우 환경에서는 더 쓰이지 않지만, 인터넷 환경에서의 파일시스템은 주로 POSIX 호환 OS들이 지배하는 관계로 여전히 네트워크에서 많이 사용되는 인코딩입니다.
0x00-0x9F 영역은 아스키 코드와 ISO 표준 제어문자가 사용하고 있는 관계로, 완성형 코드는 첫번째와 두번째 octet에서 모두 0xA1-0xFE까지를 사용합니다. 그래서 94*94 = 8836개의 코드 영역에 2350자의 한글, 4888자의 한자, 1128자의 특수문자, 470자의 기타 문자가 그야말로 '순서대로' 들어가 박혀 있습니다. 정렬할 때 문제가 없고 아스키 영역과 충돌하지 않는다는 점을 제하면 자소 추출도 테이블 없이는 불가능하고 안 써지는 글자도 많은 무책임한 인코딩. 16비트 인코딩을 고집해야 했다면 차라리 특수문자가 없었으면 좀 나았을지도 모르는데 말이죠.
ISO-2022-KR은 한글 메일 인코딩에서 사용되는 인코딩 방식입니다. 같은 국제 표준이라도 유니코드와 달리 7비트 기반인 ISO-2022는 escape 문자를 이용해 영역마다 인코딩 문자셋을 지정해주는 방식이므로, 각 octet의 첫 비트가 1이 아니라 0이라는 점을 제외하면 KS5601과 동일합니다.

2. KSSM 조합형

완성형이 나오기 전에 삼보에서 내놓아 널리 사용되었지만 표준에 채택되지는 못하다가 나중에 컴퓨터업계의 반발에 못 이겨 뒤늦게 표준으로 채택된 인코딩방식. 한글 인코딩 문제를 공학적으로 깔끔하게 해결하고 있는 나쁘지 않은 방식이지만, ISO-2022가 나오기 전에 나온 방식이라 국제 표준으로 채택되는 데 무리가 있었고, 덕분에 금방 사용자들에게서 잊혀지고 말았습니다.
16비트 중 처음 1비트를 제하고, 나머지 15비트를 초성/중성/종성에 각각 5비트씩 할당하여 인코딩하고 있습니다. 문제는 이 중성 5비트중 3번째 비트가 2번째 octet의 첫 비트가 되는데, 이 3번째 비트에서 0을 사용하는 모음들이 있어 뒤쪽 octet이 ascii code와 어쩔 수 없이 겹치게 된다는 점이죠. 그래서 영어 한글자로 조합형 문서 내에서 검색을 수행하는데 엉뚱하게 한글 글자가 검색에 걸리는 문제가 발생합니다. 완성형은 양쪽 octet에서 모두 코드 영역을 0xA1-0xFE로 제한하여 글자수가 치명적으로 줄어들었지만, 아스키 영역과 충돌하지 않는 장점이 있었고, 덕분에 ISO2022에 채택될 수 있었습니다. 덕분에 DOS나 유닉스에서는 완성형을 운영체제 표준으로 채택하게 되었고, 조합형은 완전히 기억에서 사라진 것이죠.
물론 조합형이 사용되지 않게 된 것에는 이것 말고도 여러가지 정치적인 이유도 있습니다만, 기술적인 이유가 없었던 것도 아니라는 뜻입니다. 그래도 도스 시절엔 뜻있는 많은 사람들의 지지를 받았던 인코딩입니다.

3. 확장완성형(codepage 949 혹은 UHC)

codepage 949는 MS에서 내부적으로 사용하는 한국어 로케일의 코드번호입니다. 윈도우 95와 98에서 사용되었던 것으로 알고 있으며, 이후 비 NT 커널이 완전히 퇴출당하면서 사라졌습니다. 완성형이 자소 추출 코드를 짜기가 불편한 정도였다면, 확장완성형은 프로그래머 입장에서는 완전히 악몽같은 인코딩입니다. 음절 개수를 추가하느라 0xA1-0xFE 바깥의 새로운 코드영역([0x81-0xA1][0x41-0xFE], [0xA1-0xC6][0x41-0xA0])을 사용하기 때문에 프로그램을 별 생각없이 짜면 ascii code가 검색에 걸리는 경우가 생기는데다가, euc-kr에서 이미 정의해둔 영역은 건드리지 않고 새로운 영역에 군데군데 빠진 글자들을 추가하느라 이 부분을 적절히 변환해주지 않으면 정렬조차 제대로 되지 않습니다.
물론 윈도우 api가 이런 부분을 어느정도 보완해주기는 하지만, 도저히 일반적인 목적으로는 써먹을 수 없는 인코딩이죠. 여전히 FAT32 파일시스템에서는 이걸 사용하고 있는 것으로 알고 있습니다. 지나간 악몽으로 치부하기엔 아직 무리가 있는 것 같군요.

4. 유니코드 인코딩

ㄱ. 유니코드 소개

이제 유니코드가 등장하면서 한글 인코딩과 관련된 문제들은 모두 해결되었다! 고 외칠 수 있으면 얼마나 좋겠습니까마는, 문제는 간단치 않습니다. 여기서는 UCS-2와 UTF-8만 소개하겠지만, 같은 유니코드라도 버전이 1.0에서 4.1까지 벌써 다종다양하고, 같은 버전에서도 인코딩 방식이 서로 달라서 통일된 인코딩 문제는 아직도 험난하기만 합니다.
유니코드에 왜 이런 문제가 존재하는지 알기 위해서는 유니코드에 대해 정확히 이해해야 합니다. 일단 유니코드는 만국 공통으로 사용할 수 있는 하나의 표준화된 코드를 제정하기 위한 두 단체, 즉 기업들의 주도로 이루어진 유니코드 컨소시엄과 ISO 표준안의 하나였던 ISO/IEC 10646 사이의 타협의 결과입니다. 세계에 존재하는 모든 문자들에 각각 서로 다른 번호를 붙여 사용함으로서 같은 문서 내에 여러가지 문자들이 공존할 수 있게 하려는, 꽤나 기특한 프로젝트지요.
그러나, 이 많은 문자들이 기존의 8bit 인코딩 안에 들어갈 리는 없고, 기존의 8bit 기반 문서와 호환은 하고 해야 하니 여기서부터가 딜레마의 시작이 됩니다. 그래서 유니코드는 character set과 encoding의 두 가지로 문제를 분리했습니다. character set은 전 세계 문자들에게 서로 다른 번호를 부여해 그것을 table로 만드는 것이고, encoding은 그렇게 부여된 번호를 어떻게 기록하는가의 문제입니다. UCS-2와 UTF-8은 바로 encoding 방식을 가리킵니다. 다행인 점은 이들 encoding scheme은 character set을 어떻게 코드로 변환할 것인가 하는 알고리즘의 문제라서, 테이블 없이 간단한 함수를 통해 인코딩 방식을 서로 전환하는 것이 가능합니다. 이정도만 해도 국제표준을 제정한 보람이 있다 하겠지요.

ㄴ. 유니코드의 한글 영역

유니코드 character set에서 한글이 차지하는 영역은 세 개로 나눌 수 있습니다. 첫번째는 0x1100-0x11F9 까지의 한글 자모 영역. 한글에서 사용되는 자모들을 초성 자음/중성 모음/종성 자음으로 각각 나누어 한글자씩 대응시킵니다. 두번째는 0x3130-0x318E까지의 한글 호환 자모 영역. 이 부분은 초/중/종성을 구분하지 않고 그냥 사용되는 모든 자모들이 한데 묶여 들어 있습니다. 세번째는 0xAC00-0xD7A3까지의 한글 영역. 이 부분에는 현대 한글 자모로 표현 가능한 모든 한글 문자들이 들어 있습니다. 조합형 한글의 장점도 함께 갖고 있어, 두세줄의 코드를 통해 자모를 추출하는 것도 가능합니다. 그 외 한자들은 다른 영역에 포함되어 있습니다.

ㄷ. UCS-2

UCS-2는 이렇게 지정된 character set을 단순하게 16bit로 인코딩합니다. NT계열 OS에서 사용하고 있는 방식이지요. 심플하지만 이전까지의 8bit 인코딩 방식을 사용하는 프로그램과 어쩔 수 없이 충돌을 일으켜야 하는 문제점을 지니고 있습니다. 이 인코딩 방식은 유니코드 3.x까지만 유효한데, 유니코드 4.x 부터는 문자 개수들이 너무 많아 도저히 65,536개의 번호로 다 나타낼 수 없었기 때문입니다. 사실 이 문제는 예전부터 예견되어 왔던 문제입니다. 알려진 한자의 개수만 10만개가 넘는 걸로 알려져 있으니 말이죠. 때문에 유니코드 3.1부터는 20bit의 코드 영역을 가지고 백만개의 글자를 표현할 수 있도록 character set의 체계를 변경하였습니다. 그에 맞추어 UCS-2 대신 32비트 인코딩 방식인 UCS-4도 함께 소개되었습니다만, 아직 이 방식을 사용하는 프로그램은 없는 것으로 알고 있습니다.

ㄹ. UTF-8

UTF-8은 이전까지의 8bit 방식 프로그램들과의 호환성을 목표로 만들어진 인코딩 방식입니다. 물론 20bit에 매핑된 코드들이 8bit 256개의 코드 안에 다 들어가는 것은 물론 아니므로, UTF-8 방식은 가변 길이 인코딩 방식입니다. UTF-8에서는 U+0000 ~ U+007F까지의 128자는 1바이트로 표현되는데 이는 ASCII와 동일합니다. 이로서 호환성을 간편하게 유지할 수 있죠. 또 U+0080 ~ U+07FF까지는 두 바이트, U+0800 ~ U+FFFF까지는 세 바이트로 표현됩니다. 그 이후의 코드들도 각각 인코딩 영역을 갖고 있어 최대 여섯 바이트 내에서 20bit로 인코딩된 문자셋 상의 모든 문자들을 표현할 수 있게 됩니다.
UTF-8은 가변길이라는 약점이 존재하지만, 그 점을 제하면 용량 절약에도 상당히 도움이 되고 아스키 코드 기반인 유닉스 파일시스템과도 호환이 비교적 간편한 좋은 인코딩 방식입니다. 한글 인코딩 문제를 걱정하는 많은 분들이 네트워크상의 한글 문서들을 차차 UTF-8으로 변경해야 한다고 생각하고 계시는 모양이지만, 윈도우 파일시스템과 호환이 되지 않아 좀처럼 여의치 않은 것 같습니다.

여기까지 요 며칠간 공부한 내용을 간단히 정리해 보았습니다. 이중에 뭐가 한글을 위해 가장 나은 방법인지는 저도 잘 모르겠어요. 유니코드가 제일 좋은 대안인 것은 확실하지만, 인코딩에서 갈등이 존재해서야 이전보다 상황을 복잡하게 만들 뿐인 것 같기도 하고... 윈도우가 과감히 UTF-8을 채택하거나 유닉스 시스템들이 UTF-16으로 전환해 준다면 제일 좋을 것 같기도 한데 말이죠.
tag