델파이 (개발툴)

한 달쯤 전에 비주얼 베이직 리뷰를 쓴데 이어 오늘은 델파이와 해당 계열 RAD 툴의 리뷰를 좀 써 보겠다.
비주얼 베이직뿐만이 아니라 델파이와 C++ 빌더(C++ Builder)는 본인이 지금 같은 골수 비주얼 C++ 유저가 되기 전에, 도스에서 윈도우 프로그래밍으로 넘어가던 과도기 시절에 잠깐 써 본 개발툴이다. 고등학교 시절의 추억이 담겨 있다.

일단 파스칼이라는 언어 자체가 본인이 베이직에서 C/C++로 넘어가기 전에 과도기적으로 잠깐 공부했던 언어이다. 당시 정보 올림피아드 공부용으로 파스칼이 아주 깔끔하고 좋다는 말이 있기도 했고 말이다. 이 언어는 정말로 베이직과 C 사이의 과도기 역할을 하면서 본인의 프로그래밍 패러다임의 전환에 굉장한 도움을 주었다.

도스용 볼랜드 파스칼 역시 상당히 잘 만든 개발툴이었다. 그래서 본인은 이걸로 뭔가 이렇다할 프로그램을 개발해 보지 못한 게 좀 아쉽다. 개발툴의 본좌(?)이던 마이크로소프트와 볼랜드는 둘 모두 도스에서는 16비트의 한계를 벗어나질 못했으니 말이다. 그리고 지금 역시 <날개셋> 한글 입력기처럼 극도의 최적화를 추구해야 하는 프로그램은, 비주얼 C++만치 더 적격인 툴이 없는 것도 어쩔 수 없는 현실이다.

1990년대 초중반에 마이크로소프트가 '비주얼' 브랜드로 새로운 개발툴을 내놓은 것처럼 볼랜드는 오브젝트 파스칼 기반의 완전히 새로운 RAD 툴을 내놓았다. 그것이 바로 델파이. 게다가 1995년에 첫 출시된 1.0은 전무후무하게 16비트 윈도우용이었다.

델파이는 원래 AppBuilder라는 제품명이 붙을 예정이었고 Delphi는 코드명일 뿐이었다. 내 기억이 맞다면 이에 대해서 재미있는 일화가 전해진다.
잘 알다시피 IT계엔 그 이름도 유명한 Oracle이라는 데이터베이스 엔진(DBMS)가 있다. 이거 참 센스 있는 작명인게, DB에다가 SQL을 때려서 쿼리가 수행되는 것을 마치 신탁을 내리는 것에다 비유한 것이다. “수천만 개의 레코드 중에서 요것과 연계하여 이런 조건을 만족하는 놈을 눈앞에 0.1초 안에 대령하라.” 검색 엔진에다 심마니라는 이름을 붙인 것과 비슷한 맥락의 작명이라 하겠다.

그런데 신탁이 내려지는 곳이 어디던가? 신전이다. 그리고 고대 그리스에는 델파이라는 도시에 아폴로 신전이 있었다.
델파이는 DB와 연동하는 업무용 프로그램을 파스칼 언어를 기반으로 빠르고 편리하게 개발해 내라고 만들어진 개발툴이다. 그래서 DB 쿼리라는 신탁이 내려지는 장소에다 빗대어 델파이라는 코드명이 정해졌고, 이게 곧 제품명이 되었다. (뭐, 굳이 DB를 안 쓰더라도 각종 유틸리티나 에디터, 툴을 만드는 용도로도 좋지만 말이다.)

이런 이유로 인해, 델파이는 지금까지도 신전이나 집 비슷한 모양을 한 아이콘을 갖고 있다. 델파이의 C++ 버전이고 델파이보다는 훨씬 덜 유명한 C++ Builder는 집+크레인처럼 생긴 건축 기계 모양 아이콘이다. C++ 빌더는 다른 건 델파이와 비슷한데 역시 C++의 특성상 빌드 속도는 훨씬 더 느리며, RAD 툴의 용도에 맞게 C++ 문법을 자기 식대로 확장한 게 좀 있다. 또한 C++답게 경쟁사의 MFC 라이브러리도 내장하고는 있다.

그런 곳에서는 C++의 위상이 좀 므흣한 게, 닷넷으로 치면 마치 C++ managed extension 같은 존재이다. 닷넷에서는 아예 확실하게 C#을 쓰고 필요한 곳에나 unsafe 코드를 가끔씩 집어넣고 말지, 네이티브 기계어 개발이 아니라면야 C++이 얼마나 메리트가 있겠나 싶다. C/C++을 쓸 정도이면 아예 Win32 API만을 이용한 하드코어 저수준 개발을 하지, 애초에 RAD용으로 만들어진 게 아닌 언어에다가 그 정도로 추상화 계층을 거친 RAD 껍데기를 거추장스럽게 씌울 필요가 있겠나 하는 생각이다.

볼랜드에서는 자기네 RAD 툴에다가도 닷넷 기술을 연동하여 C# Builder 같은 툴을 만들기도 했지만 이건 얼마 못 가 접었다. 다들 비주얼 C#을 쓰지 굳이 볼랜드 툴을 쓰지 않았기 때문. 볼랜드는 그런 자신의 RAD 영역을 더욱 발전시켜서 마치 qt 같은 크로스 플랫폼 개발 프레임워크를 표방하며 리눅스용으로 카일릭스(Kylix)도 내놓고, 지금은 맥 OS X 범용 개발 환경도 내놓았는데, 아이디어는 분명 좋다만 결과는 과연 어떨까 궁금하다. 카일릭스는 수 년 전에 망했고 개발이 중단됐다.

하긴, 말이 나왔으니 말인데 얘들은 개발사의 명칭이나 주체가 여러 번 바뀌었다(개명· 인수 합병). 볼랜드이다가 한때는 Inprise, Codegear를 거쳐 지금은 Embarcadero임.

이런 저런 사정이 많았으나 델파이는 결국 오늘날까지도 그냥 윈도우 플랫폼 한정으로 강세인 것으로 보인다. 나름 네이티브 코드(오옷!)를 가히 C++로는 엄두를 못 낼 전광석화의 속도로 생성하는 RAD 툴이니, 생산성은 확실히 우위이다. 프레임웍에 속하는 코드가 단일 exe에 모조리 static 링크되어 들어가기 때문에, Hello world 급의 프로그램도 Release 빌드의 exe는 1MB 이상은 먹고 들어간다.

비주얼 C++ 2008 이상부터는 MFC를 static link해도 그 정도는 먹고 시작한다. 과거의 6.0 시절에는 MFC의 static link 오버헤드 크기가 200~300KB대였는데, 재미있게도 그 당시의 델파이 2~3도 exe의 기본 크기가 그 정도였으니 옛날이나 지금이나 오버헤드가 서로 비슷하다.

이런 이유로 인해, 델파이로 개발된 프로그램은 실행 파일을 실행 파일 압축기로 압축한 채 배포되는 경우가 종종 있다. 하지만 압축된 실행 파일은 코드 실행 영역이 동적으로 생성되고 고쳐지기 때문에, 동일 EXE가 중복 실행되었을 때 코드 영역이 동일한 물리 메모리를 공유하여 메모리를 절약하는 효과를 못 보지 싶다. 실행 파일 압축기가 집어넣어 준 압축 해제 stub이 그런 걸 똑똑하게 감지하여 처리하지 않는다면 말이다. 뭐, 요즘은 어차피 메모리도 차고 넘치는 시대이긴 하지만...;;

내 기억이 맞다면, C++ Builder는 델파이와는 달리 수 MB짜리 vcl.dll (Visual Component Library) 런타임이 필요한 작은 exe를 생성했었지 싶다. 즉, 정적 링크가 아니라 동적 링크 방식.

그런데 얘들의 프레임웍 라이브러리는 덩치만 큰 게 아니라 윈도우 API를 나름 체계적으로 잘 커버하고 있다. MFC는 윈도우 API에다 아주 최소한의 껍데기만 씌운 것에 가까운 반면, 볼랜드의 라이브러리는 운영체제 API에는 존재하지 않는 여러 추상적인 계층을 더 만들고, 심지어 같은 에디트 컨트롤도 single line (TEdit)과 multi line (TMemo) 버전을 따로 만들었다. MFC는 그냥 CEdit 하나로 끝인데 말이다. 내부 구현이 옵션만 다르게 지정된 동일한 에디트 컨트롤이니까 말이다.

라디오 버튼이나 체크 버튼도 under the hood는 그냥 버튼 컨트롤일 뿐이기 때문에 MFC는 CButton 하나로 끝이다. 그러나 볼랜드의 라이브러리는 응당 TRadioButton과 TCheckBox로 클래스가 따로 나뉘어 있다.
볼랜드의 프레임워크는 DC고 GDI 객체고 나발이고 생각할 것 없이 자기네가 마련한 TCanvas라는 개체를 통해 마음대로 색깔을 바꾸고 픽셀 단위 그래픽 접근이 가능한 반면, MFC에서는 그런 자비를 찾아볼 수 없다. 그런 추상화 계층을 마련하는 오버헤드가 exe의 실행 파일 크기 내지 런타임 DLL로 나타난다고 생각하면 됨.

이런 전통이 사실 볼랜드의 옛 C++ 라이브러리인 OWL (Object Windows Library)부터 어느 정도 전해져 오고 있었다. 델파이가 나오기 전, 볼랜드 C++/파스칼이 윈도우용으로 있던 시절 얘기이다. OWL이 좀 더 객체 지향 철학을 살려서 더 잘 만들어진 라이브러리이긴 했으나, 언제부턴가 IE가 넷스케이프를 누르듯이 MFC가 OWL을 떡실신시켜 버렸다.

세월이 세월이다 보니 델파이도 도움말 레퍼런스는 MS 비주얼 스튜디오의 Document Explorer를 쓰고 있어서 뜻밖이라는 생각이 들었다. 하긴, 옛날 버전은 아예 WinHelp를 쓰고 있었는데, 자기네만의 도움말 시스템을 새로 만드는 건 너무 뻘짓이고 그냥 chm을 쓰기엔 레퍼런스의 분량이 너무 방대한데, 저렇게 하는 게 나은 선택이다.

델파이의 근간 언어인 파스칼은 내부적으로 문자열을 포함하는 방식이 원래 C/C++과는 다르다. 그러나 운영체제의 각종 API들이 오로지 C/C++ 스타일의 null-terminated 문자열만을 취급하기 때문에 델파이 프로그래머도 C/C++ 스타일 문자열이라는 개념을 몰라서는 안 된다. 사실 파스칼과 C/C++은 함수 호출 규약조차도 달라서 과거에는 C/C++에서도 함수 선언할 때 STDCALL뿐만이 아니라 PASCAL이라는 속성이 있을 정도였다.

파스칼에도 포인터가 있긴 하다. 하지만 C/C++만치 배열과 포인터를 아무 구분 없이 남발할 수 있는 건 아니며 쓰임이 제한적이다. a[2]뿐만이 아니라 2[a]까지 가능한 건 가히 C/C++의 변태적인 특성이다만, 파스칼은 등장 초기에는 동적 배열이라는 개념 자체가 아예 없었다고 한다.
타입 선언에서 포인터를 의미하고 실제 수식에서는 포인터가 가리키는 값을 얻어오는 연산자가 C/C++은 *인데 파스칼은 ^이다.
그리고 이미 있는 변수의 주소를 얻어 오는 address-of 연산자는 C/C++은 &이고, 파스칼은 @이다.

델파이로 개발된 프로그램은 윈도우 비스타/7의 Aero 환경에서 창을 최소화해 보면 창이 작업 표시줄 쪽으로 미끄러지듯 fade out이 되지 않고 그냥 혼자 싹 없어지곤 했다. 나타나는 비주얼이 살짝 다르다. 델파이로 빌드된 다른 프로그램들을(특히 구버전) 살펴보면 차이를 알 수 있다.

그랬는데 최신 2011년도 델파이 XE2로 프로그램을 하나 빌드해 보니까 드디어 여타 프로그램처럼 제대로 최소화된다. 개선이 된 듯하다.
델파이가 유니코드와 64비트를 제대로 지원하기 시작한 것도 생각보다 최근이라고 들었다만.. 앞으로 이 툴이 어디까지 발전하고 MS의 비주얼 툴과는 다른 독자적인 지위를 유지할 수 있을지가 지켜보는 건 흥미로운 일일 것이다.

* 2014년 7월 1일 추가함.
델파이 1.0은 특정 업종 종사자들만 사용하는 딱딱한 개발툴인 주제에 무슨 게임을 방불케 하는 화려한 설치 화면을 자랑했다.

사용자 삽입 이미지

설치 프로그램이 full screen 모양으로 실행되는 게 유행이던 시절의 즐거운 추억이다. 본인도 중학생이던 시절 저 화면을 직접 본 적이 있다. 정말 개발툴 역사상 전무후무한 디자인이 아닐까 싶다.

속도계는 어떤 축적된 분량이 아니라 단위 시간당 변화량 개념이기 때문에,
굳이 이런 프로그램에 넣더라도 차라리 지금 파일의 전송 속도를 나타내는 용도가 더 적절할 것 같다만..;;
어쨌든 저 계기판에서 속도계가 전체 설치 진행 상황을 나타낸다.

굉장한 창의력과 잉여력이 아닐 수 없다. 그때는 MS Office 9x 프로그램에도 간단한 핀볼이나 3D 레이싱 게임이 이스터 에그로 들어가 있었을 정도이니 뭐...
단, 델파이의 경우 설치 중에 저 배경에서 차가 실제로 주행하여 배경이 입체적으로 스크롤된다거나 하지는 않는다. ^^ 그건 일말의 아쉬운 점이다.

Posted by 사무엘

2012/02/27 19:10 2012/02/27 19:10
, , ,
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/647

살다 보니 C#이나 파이썬도 아니고 비주얼 베이직으로 작성된 코드를 C++로 포팅해야 할 일이 있었다. C/C++로 갈아탄 뒤로는 베이직 코드는 다시는 볼 일이 없을 줄 알았는데 이거 정말 몇 년 만이냐.

들여다봐야 하는 코드는 닷넷도 아니고 비주얼 베이직 6으로 만들어진 코드였다. 하지만 GUI가 아니라 계산 알고리즘을 포팅하는 것이기 때문에 포팅이 크게 어려운 건 없었다. VB6에서 닷넷으로 넘어가면서 완전히 뒤집어엎어진 건 API 체계이지, 언어 자체가 그렇게 많이 바뀐 건 우려한 것만치 많지 않아 다행이었다. 자바와 자바스크립트의 관계에 필적하는 이질감은 아닌 것 같다.

언어가 바뀐 것은,
- 첫째, statement이던 것이 C 언어의 영향을 받아 다 일관된 함수 호출 형태로 바뀜. 그래서 매개변수 전체를 괄호로 싸야 됨. (파이썬도 3.0에서는 print가 statement에서 함수로 바뀜)

- 둘째, 타입이 예전보다 더 엄격해지고, 모든 변수는 반드시 사용 전에 선언을 해 줘야 함. 베이직은 원래 그런 걸 안 하는 언어이다가 하는 걸로 바뀌었다 보니, 변수를 선언하는 키워드가 Var이 아니라 Dim...이다. 원래는 배열을 선언할 때만 쓰는 키워드였지.
이런 추세를 정면으로 역행하는 GWBASIC의 잔재인 DefINT A-Z 같은 명령문은 당연히 퇴출이다.

- 셋째, 그리고 객체지향 패러다임에 맞춘 API의 전면 재구성이다. 예전엔 그냥 global 단위로 곧바로 호출하던 함수도 다 분야가 나뉘어서 클래스나 namespace에 소속된 메소드로 바뀌었다. 그래서 수학 함수도 바로 Sqrt라고 하면 안 되고 Math.Sqrt라고 써 줘야 하며, Math를 자주 쓴다면 Using 선언을 한 뒤에 생략해야 한다. 하긴, 비베에는 예전부터 With 키워드는 있긴 했다만.

이 정도.
요즘 언어들은 C/C++ 영향을 받아서 다들 대소문자 구분을 하는 게 유행이기 때문에, 혹시 비주얼 베이직도 그렇게 바뀌지 않았으려나 생각했다만...
의외로 명칭에 대소문자 구분을 안 하는 건 VB6이나 닷넷이나 마찬가지이다.

베이직은 원래 좀 가볍고 동적인 언어였는데, MS의 닷넷 입맛대로 대수술을 거치다 보니 그냥 C#의 표현력에 필적하는 전형적인 절차형 언어가 된 것 같은 느낌이 든다. 예전의 베이직 같은 느낌은 파이썬이 더 잘 간직하고 있는 듯.

배열 첨자도 ()로 싸고, 함수 호출 인자도 ()로 싸는 건 베이직의 특징이다. 언뜻 보기에 굉장히 혼동될 것 같은데 C++처럼 [] () 따로 연산자 오버로딩이라도 해야 하는 게 아니라면 의외로 둘이 문법 차원에서 혼동될 일은 없다. 참고로 본인은 ::와 .의 구분이 없는 객체지향 언어들에 대해서도 의아해한 적이 있었는데 이 구분 역시, 포인터만 없다면 거의 필요하지 않다.

그러고 보니 베이직은 대입도 =, 동등 비교도 =이다. A=B=1이라고 하면 C언어 식으로 치자면 A=B==1처럼 해석된다. 원래 베이직의 대입문은 Let A=1 처럼 써 줘야 맞는데 Let이 C언어의 auto만큼이나 캐잉여로 전락하는 바람에 지금 같은 꼴이 된 것이다. 그러고 보니 Let을 Dim처럼 변수 선언 키워드... 아니 C++0x의 auto처럼 쓰는 것도 괜찮을 것 같다?

Dim A as Double
Dim I as Integer

뿐만 아니라

Let A = 0.52 '자동으로 실수 확정
Let I = 5    ' 자동으로 정수 확정

이렇게도 되게 말이다. 타입이 이랬다저랬다 바뀌는 Variant가 아님. 기발하지 않은지? ㄲㄲ

베이직처럼 구문 분석이 쉬운 언어는 IDE의 인텔리센스나 코드 자동 완성 같은 기능이 C++의 그것과는 비교할 수 없이 안드로메다급으로 훨씬 더 빠르고 똑똑하고, 돌아가는 게 손에 착착 달라붙는다. 도스 시절의 퀵베이직이 이미 인텔리센스만 없을 뿐이지 그런 꿈의 프로그램 개발 환경을 어느 정도 제공하고 있었다. 빌드 속도는 두말 할 나위도 없음.

그러나 C++ 코드는 실시간으로 코드 변경 사항을 IDE가 따라잡으려면, 비주얼 스튜디오든 Source Insight든, 어쨌든 background에서 소스를 다 까 보는 작업을 하지 않으면 안 된다. 그래서 어떻게든 처리 속도를 올리려고 덕지덕지 남기는 부가 정보 데이터가 많다. 함수 이름을 바꾼 게 C/C++은 복잡한 절차를 거쳐 최소한 수 초 뒤에 IDE의 ClassView에 반영되는 반면, 베이직은 ‘즉시’이다.

이런 생산성과, C++ 특유의 졸라 가볍고 효율적인 네이티브 코드라는 두 마리 토끼를 모두 잡은 프로그래밍 언어 + 개발 환경은 정녕 없는 것일까.
하긴, 윈도우 환경에서 베이직 언어로 네이티브 코드를 생성하는 컴파일러는 MS 제품 중에는 없고 파워베이직이라는 브랜드가 있다. 하지만 인지도가 안습한 수준.

Posted by 사무엘

2012/01/26 08:45 2012/01/26 08:45
,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/632

서식을 지원하지 않는 단순한 텍스트 에디터를 워드 프로세서로 발전시키려면 무슨 작업이 필요할까?
뭐니뭐니해도 글자마다 서식을 달리 지정할 수 있어야 한다. (서체, 속성, 크기, 색깔 등등)
그런데 그걸 구현하는 과정에서 개념적으로 굉장히 중요한 결정을 내려야 하는 게 있다. 바로, 장치 독립적인(device-independent) 레이아웃을 구현하는 것이다.

장치 독립이란, 표시 화면의 해상도(=확대 배율)와 관계없이 글자들의 비율과 위치가 일정하게 유지되는 걸 말한다. 쉽게 말해 위지윅(WYSIWYG)이다. 요즘 워드 프로세서에서는 필수인 이 기능을 지원하기란 장치 종속 레이아웃보다 훨씬 더 어렵다.
우리에게 잘 알려져 있는 장치 종속 레이아웃과 장치 독립 레이아웃의 예는 다음과 같다.

장치 종속적 레이아웃: 웹브라우저 화면. MS 엑셀. MS 워드의 웹/개요 모드, Draft/normal view. 워드패드
장치 독립적 레이아웃: MS 워드의 인쇄 모드(print layout) view. 아래아한글, Acrobat PDF, 그리고 모든 프로그램들의 '인쇄 미리보기 (print preview)'

차이를 아시겠는가?

WWW
iiiiiiiiiiiii

가변폭 글꼴로 두 줄에 W와 i를 비슷한 폭이 되는 개수로 찍은 뒤(당연히 i의 개수가 훨씬 더 많아짐),
화면 배율을 아주 작게 줄였다가 아주 크게 확대해 보라.
W와 i의 폭의 편차가 크면 장치 종속적인 레이아웃이고,
대체로 전반적인 배율은 잘 유지되지만 그 대신 작은 크기에서 i들끼리의 픽셀 간격이 들쭉날쭉하다면(저해상도에서 보정을 위해 어쩔 수 없이) 그건 장치 독립적인 레이아웃이다.

엑셀을 실무에서 오래 써 본 분들은 이미 아시겠지만, 엑셀은 심지어 Page layout view에서도 위지윅이 전혀 보장되지 않기 때문에 화면에서 보는 글자의 폭과 인쇄해서 보는 글자의 폭의 차이를 유의해야 한다.
화면으로 보기 좋게 글자수나 폭을 맞춰 놓은 것은 인쇄를 하거나 심지어 확대 배율만 바꿔 봐도 모조리 어긋나 버리기 때문이다.
편집 화면이 아니라 오로지 '화면 인쇄'만이 장치 독립성이 보장되는 결과를 보여준다.
엑셀은 대용량의 데이터를 수월하게 다루기 위해서, 성능상의 이유로 위지윅 편의는 희생한 셈이다.

요즘 워드 2007은 처음 시작했을 때 인쇄 모드 view로 시작하지만, 옛날, 한 97~2000 버전까지만 해도 print layout이 아니라 normal view가 기본 모드였다. 아래아한글은 비슷한 개념으로 '쪽윤곽' 옵션이란 게 있어서 둘의 차이는 화면에 용지의 여백이 나타나 보이는지의 여부가 고작이지만, 워드의 normal view는 print layout view보다 훨씬 더 이질감이 컸다. 그림이나 표 같은 틀이 제 위치에 표시되지 않고 다단(column)이나 세로쓰기 같은 건 아예 무시되었으니까...;; 그리고 근본적으로 normal view는 앞서 말했듯이 위지윅이 보장되지 않는다.

이런 view가 기본 mode였던 이유는 두말 할 나위도 없이.. normal view가 문서를 훨씬 덜 정교하게 대충 렌더링하기 때문에, 처리 속도가 훨씬 더 빠르기 때문이었다.
normal에서 신나게 긴 글을 편집하고 있다가 print layout으로 처음으로 모드를 바꾸면, 워드는 “페이지를 정돈하고 있습니다. 잠시 기다려 주십시오”라고 뜸을 들이곤 했다.

장치 독립적인 레이아웃에서는 여백이나 글자 크기 따위를 나타낼 때 픽셀이 아니라 어느 매체에서도 동일한 절대적인 단위가 쓰인다. 그래서 아래아한글이라든가 PDF 같은 문서 파일 포맷 스펙을 보면 그런 개념을 찾을 수 있으며, 아래아한글의 경우는 1/n 인치가 최소 단위였지 싶다.

운영체제 API는, 해상도가 서로 넘사벽급으로 다룬 모니터와 프린터를 모두 동일 코드만으로 수월하게 다루기 위해서 다양한 추상적인 좌표계와 확대 배율을 지원하며, WM_PAINT뿐만이 아니라 WM_PRINT 같은 (잘 알려지지 않은) 메시지도 제공하고 있다.
MFC가 OnPaint말고 OnDraw라는 화면· 프린터 통합 메소드를 제공하는 것 역시 다 이유가 있어서인 것이다
.
흠, 그러고 보니 나도 포스트스크립트나 '텍' 같은 전자 조판 언어를 공부하고 싶긴 한데, 접할 기회가 없구나.;;

Posted by 사무엘

2011/08/19 09:03 2011/08/19 09:03
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/557

1.

이 블로그는 좀 특이한 구석이 있다.
보통, 덕력이 좀 높은 블로거는 전문 분야 블로그와 일상 잡담 블로그를 분리해서 운영한다.
하지만 본인은 그렇게 하지 않으며 모든 관심 분야에 대한 글을 한 블로그에다 몰아서 올린다.
블로그를 따로 운영해야 할 정도로 덕력이 아주 높은 것도 아니어서 말이다..... 어? ㄲㄲㄲㄲ

난 사람들이 자기 관심 분야 블로그에만 가는 걸 원하지 않는다.
내 근황이 궁금하고 나에 대해 알고 싶어서 내 블로그에 온 사람이라면, 좋든 싫든 프로그래밍 관련 글도 보고, 철-_-도 관련 글도 보고, 한글 관련 글, 기독교 관련 글도 보길 원한다.
독자 여러분은 어떻게 생각하실지 모르겠지만 어쨌든 본인은 내 식대로 이런 식으로 블로그를 운영해 나갈 것이다. ㅋㅋ
<날개셋> 한글 입력기 카테고리가 몇 달째 글이 없으니 오늘은 또 오랜만에 개발 근황을 전하도록 하겠다.

2.

<날개셋> 한글 입력기의 다음 버전은 6.2로 확정했다. 나흘 뒤인 8월 21일 아침에 나올 예정이다. 현재 코딩은 거의 마쳤고 테스트와 도움말 작성 중이다.
편집기를 안 쓰는 분에게는 그리 큰 해당 사항이 없겠지만, 6.2에 대해서는 지금까지 오랜 숙원이었던 에디팅 엔진의 최적화 소식부터 먼저 전해야겠다.
무려 7년 전, 3.0 시절 이래로 변함없이 남아 있던 에디팅 엔진을 뒤집어엎었다. 옛날 코드의 로직을 재구성하여 더 정교하게 다시 만드는 게 쉬운 일이 아니었다.

예전 버전이 얼마나 비효율적이었는지를 단적으로 설명하자면 이렇다.
수십만 줄에 달하는 텍스트를 불러와서 맨 앞줄에서 엔터를 눌러서 줄을 삽입하거나 텍스트를 붙여넣으면 그 줄부터 문서 끝까지 내부적으로는 행번호가 다 renumbering된다. -_-;;
그리고 undo 한번 할 때마다 그 텍스트 레이아웃이 전부 다시 짜진다.

이제는 아무리 큰 문서를 불러와도 텍스트 레이아웃과 재배치는 영향을 받은 문단에서만 일어나며, renumbering도 없어졌다. Ctrl+Z를 마음껏 눌러도 된다.
다른 작업 우선순위에 밀리고 또 밀려서 7년 동안 못 하고 있던 일을 이제야 해냈다.
3.0을 만들던 당시는 세벌식 모아치기와 새로운 한글 입력 오토마타에 치중하느라, 에디팅 엔진은 비록 구닥다리 2.x에 비해서야 혁신이었지만 그래도 시간 관계상 대충 발로 짠 부분이 있었던 것이다.

이번 버전은 파일 저장도 매 줄마다 디스크에 쓰는 게 아니라, 수 MB 단위로 버퍼에다 미리 저장한 후 한꺼번에 디스크에 쓰게 함으로써 속도를 크게 향상시켰다. 이렇게 하는 게 이 정도로 큰 차이를 만들 줄은 몰랐다.
<날개셋> 변환기의 파일 변환 속도도 훨씬 더 빨라졌다.
학교에서 실제로 수~수십 MB에 달하는 옛한글 말뭉치 파일을 다뤄 보고서야 성능을 개선할 필요를 느꼈다.

3.

그리고 <날개셋> 편집기는 이제 legacy format(한컴 2바이트 코드 및 한양 PUA)으로 클립보드를 읽고 쓰는 기능이 없어지고, 편집 메뉴에 '선택하여 붙여넣기'(Paste special) 기능도 없어진다. Paste special은 무려 <날개셋> 한글 입력기 2.0때부터 있었던 기능이지만, 이 프로그램이 텍스트에다 서식을 넣을 수 있는 워드 프로세서도 아니고 사실 필요 없는 기능이다. 유니코드 하나만 신경 쓰면 되니까 말이다.

그 대신 이 기능들은 <날개셋> 변환기로 이동한다. 다만, 지금까지 한컴 2바이트 코드를 읽는 것 말고 '쓰는' 기능은 제2수준 한자를 지원하지 않았었는데, '쓰는' 것도 가능해진다. 클립보드 변환 기능까지 그대로 지원되긴 하지만, 아래아한글 97이나 <날개셋> 무려 2.x와 텍스트 데이터를 변환하는 상황이 아니라면 이제 쓸 일은 없을 것이다. 그러니 호환성 유틸리티인 변환기로 기능 이전.
하지만 유니코드가 등장하기 전에 아래아한글이 국어 정보 처리에 끼친 영향력을 감안하면, 한컴 2바이트 코드 지원을 완전히 없애 버릴 수는 없다.;;

또한, 옛한글을 한양 PUA <-> 유니코드 5.2 형식으로 변환하는 기능은 '텍스트 필터'로도 들어가서 편집기나 외부 모듈이 즉석에서 사용 가능하게 된다. 한양 PUA의 인지도는 아직까지도 무시할 수 없기 때문에..;;
이걸 감안하면, 비록 편집기의 한양 PUA 지원 기능은 겉으로는 일관성 차원에서 사라지지만, 동일 기능이 더 유용한 다른 형태로 대체되는 셈이다.

덤으로, <날개셋> 변환기는 옛한글 변환은 지금까지 UTF16 방식의 파일밖에 지원하지 않았다가 이제 드디어 UTF8도 지원할 예정이다. 그리고 명령줄에서는 하위 디렉터리의 모든 파일을 재귀적으로 찾아서 변환하는 /S 옵션이 추가된다.

4.

이렇듯, <날개셋> 한글 입력기의 다음 버전은 편집기와 변환기가 바뀐 게 많고 외부 모듈은 변화 사항이 상대적으로 적다고 볼 수 있다. 그래도 외부 모듈이 바뀐 걸 나열하자면,

첫째, 한글 글자판을 찾을 때 무조건 맨 위의 0번부터 그 아래가 아니라, 6.0에서 추가된 개념인 '기본 입력 항목'부터 먼저 고려하기 시작했다. (진작에 이렇게 했어야지..)
둘째, 편집기와 외부 모듈을 같이 쓰는 경우, 편집기에서 프로그램의 UI 언어를 바꾸면 외부 모듈도 아쉬운 대로 그걸 따라가게 했다.

이 외에, 프로그램 전반적으로는
수식에서 ? : 연산자와 콤마 연산자가 변수를 되돌리면 거기에 바로 대입이 가능하게 문법이 확장되었으며,
정 재민 님의 제안과 도움 덕분에 몇몇 글꼴들이 최신 유니코드 규격대로 업데이트되었다.
그리고 천지인· 나랏글과 더불어 스마트폰의 3대 복수 표준 입력 방식 중 하나가 된 팬텍 SKY 방식도 예제 입력 설정 파일을 만들어서 추가했다.

텍스트 필터 중에 '일괄 치환 필터'라고, 여러 건의 바꾸기 작업을 한꺼번에 수행하고 심지어 줄바꿈 문자까지 찾기-바꾸기 문자열에 포함할 수 있는 강력한 필터가 있는데,
여기에 있던 사소한 버그를 잡고, 이 필터에 '반복 적용' 옵션을 추가했다.
이걸 잘 활용하면 [   a   ], [ b  ] 같은 문자열도 싹 다 [a], [b] 같은 식으로 일괄적으로 공백 정리를 할 수도 있다. 이런 기능을 넣을 생각을 지금까지 왜 안 했는지 모르겠다.
적은 노력에 비해서 무척 유용할 수 있는 기능을 찾아내서 구현하는 건 참 즐거운 일이다.

끝으로, 타자연습은,
문장 연습 중에 오타를 내고서 Ctrl+Z를 눌렀을 때, 텍스트가 없어진 뒤에도 텍스트 위의 오타 마크가 사라지지 않던 버그를 잡았다.
그리고 게임은 이제 레벨이 올라갔을 때 자동 저장을 해 주지 않는다. 게임 중에 사용자가 단축키를 눌렀을 때만 해당 단계의 점수, 방어력, 주인공으로 나중에 게임을 이어서 할 수 있게 그 상태가 저장된다. 따라서 해당 단계의 초반에 저장을 하든, 끝날 때가 다 돼서 저장을 하든 그건 상관없다.

<날개셋> 타자연습의 게임 저장 체계는 어찌 보면 페르시아의 왕자 1의 그것과 비슷해졌다고 볼 수 있다.
(레벨의 첫 시작 시점만 저장할 수 있고, 한 시점만 저장 가능하다는 점에서)

5.
끝으로 여담,
<날개셋> 편집기처럼 텍스트 에디터를 처음부터 새로 만든다는 건 결코 쉬운 일이 아니다.
특히 유니코드의 complex script를 완벽하게 지원하려면 이미 거의 워드 프로세서 수준에 도달한다. 커서 이동, 마우스 포인터 위치로부터 문자열 위치 판단, 문단 정렬 같은 기본 중의 기본 작업들조차 완전 어려운 작업이 되기 때문이다. 내 프로그램은 그런 자질구레한 건 개발의 주목적이 아니기 때문에 죄다 깔끔하게 무시하고 개발되는데도 이 작업만으로도 코드의 양이 만만찮다.

WinAPI.co.kr의 운영자로 유명한 김 상형 님은 이런 텍스트 에디터를 개발하는 튜토리얼을 제공하고 있으니 초보 개발자들에게 무척 유익하다. 요즘 세상에 저 정도 프로젝트를 대인배스럽게 공개하는 분은 정말 드문데... 관심 있으신 분은 참고하기 바란다.

<날개셋> 입력기와 타자연습의 다음 버전도 어김없이 예전 버전과의 API 호환성은 깨질 예정이다. =_=;;; 따라서 둘을 원활히 같이 쓰려면 둘을 모두 업데이트해야 한다.
이제는 좀 바꿀 일이 없겠지 싶은 요소들도 계속 바뀐다. 그만큼 <날개셋> 한글 입력기는 여전히 활발하게 개발이 진행 중이고 살아 있는 프로젝트라는 뜻이기도 하다.

당초 계획했던 한자 관련 기능을 추가 못 하고, 입력기 커널에 내가 원하는 기능을 여건상 못 넣었는데, 이건 올해 하반기에 나올 또 다음 버전에서 기약을 해야겠다.

Posted by 사무엘

2011/08/17 08:11 2011/08/17 08:11
,
Response
No Trackback , 11 Comments
RSS :
http://moogi.new21.org/tc/rss/response/556

예전에 본인이 글로 쓴 적도 있고, 상식 차원에서 이미 아시는 분도 있겠지만..
프로그래밍 언어마다 문자열을 다루는 방식엔 차이가 존재한다.
C/C++은 null-terminated 문자열이라는 단순하고 독특한 체계를 사용하는 반면, 다른 언어들은 그렇지 않다.
그렇기 때문에, 문자열 상수가 실행 파일 내부에 어떤 형태로 박혀 있는지를 추적하면, 이 프로그램이 무슨 언어로 만들어졌겠는지 추측이 어느 정도 가능하다.

과거의 도스 시절에는 볼랜드 사에서 개발한 터보 시리즈의 컴파일러가 인기가 많았다. C/C++과 파스칼이 기억에 남는다. 이 볼랜드 제품은 당시 타사의 컴파일러가 제공하지 않던 두 가지 독자적인 기능이 있었다. 하나는 깔끔하게 잘 만들어진 IDE(에디터)였고, 다른 하나는 BGI(볼랜드 그래픽 인터페이스)라고 일컬어지는 그래픽 API였다.

한 IDE에서 프로그램을 바로 빌드-실행-디버그할 수 있으니 프로그램 개발 생산성이 뛰어나고 굉장히 편리하다. 이에 덧붙여, 그래픽은 그렇잖아도 printf 같은 표준화된 API 규격이 전무해서 ‘싸제’ 라이브러리에 의존할 수밖에 없던 영역인데, 자체 개발 라이브러리가 있다 보니 볼랜드의 컴파일러는 폭발적인 인기를 모을 수밖에 없었다.
bgidemo라고 유명한 그래픽 API 예제 프로그램도 있었는데 기억하는 분이 있으려나 모르겠다. QBasic용 예제 프로그램인 nibbles, gorilla 게임과 비슷한 시기에 만들어진 그 시절 추억이다.

사용자 삽입 이미지

아래의 스크린샷은 이 BGI 라이브러리를 사용해서(=링크해서) 만들어진 어느 EXE 파일 내부를 들여다본 모습이다. 그래픽 라이브러리이다 보니 내부적으로 출력하는 에러 메시지 문자열, 가령 No error, (BGI) graphics not installed, 심지어 Out of memory in flood fill 같은 친숙한 문자열이 내장되어 있음을 알 수 있다. 그런데 동일한 문자열들 사이에 한 놈은 ▲, →, ← 같은 이상한 기호가 듬성듬성 끼어 들어가 있다. 왜 그럴까?

사용자 삽입 이미지

사용자 삽입 이미지

기호가 없는 프로그램은 C언어(=터보 C)로 만들어진 프로그램이다. 왼쪽의 16진수값을 보면 알겠지만, 이들은 모든 문자열들이 그냥 0번 문자로 구분되어 있다.
그러나 기호가 있는 프로그램은 파스칼로 만들어진 프로그램이다. ▲, →, ←은 다음에 뒤따르는 문자열의 길이를 의미한다. 예를 들어 “▲Graphics hardware not detected”를 보면 ▲의 코드 번호는 0x1E, 즉 30인데 그 에러 메시지의 길이는 30바이트임을 알 수 있다. 얘네는 반대로 문자열들 사이에 0번 문자가 전혀 존재하지 않는다.

실제로 C/C++ 말고 String이 built-in type으로 존재하는 언어들은 이렇게 글자 수를 따로 저장해 놓는 방식으로 문자열들을 관리한다. 베이직으로 만들어진 프로그램도 QuickBasic이든 PowerBasic이든 문자열 상수들을 들여다보면 비슷한 결과를 얻을 수 있다. 그래서 이런 언어는 문자열의 길이를 구하는 함수의 시간 복잡도가 O(1)인 반면, C언어만 strlen의 시간 복잡도는 O(n)이다.

베이직 언어들은 문자열의 길이가 16비트 정수로 저장되던 반면, 터보 파스칼은 문자열 길이를 달랑 8비트 크기로 저장하여, 문자열의 길이가 256자를 넘을 수 없다는 한계가 존재했다. 흠;;

파스칼로 만든 프로그램을 들여다보면 Runtime error 같은 문자열도 존재한다. 이 역시 C/C++로 만들어진 프로그램에서는 디버그 빌드가 아닌 이상 있을 수 없는 개념이다. C/C++은 배열 첨자 범위의 검사조차도 안 할 정도로 런타임 에러라는 개념 자체가 존재하지 않는-_- 언어이기 때문이다. 그저 컴퓨터 다운(도스 시절)이 아니면 segmentation/page fault(요즘 같은 보호 모드 운영체제에서)-_-만이 존재할 뿐. -_-;;

그 반면, %d, %s이라든가 Null pointer assignment 같은 문자열이 있다면 그건 99.9% C 라이브러리가 들어갔다는 뜻이고 그 프로그램은 C/C++로 작성되었다고 유추할 수 있다.

덧붙이는 말

1. 볼랜드는 BGI 라이브러리만큼이나 텍스트 모드용 GUI? TUI? 툴킷으로 Turbo Vision이라는 라이브러리를 개발한 것으로도 유명했다. MS가 도스용 비주얼 베이직을 잠시나마 개발했다면 볼랜드에는 이런 게 있었던 셈. 당장 터보 C++과 파스칼의 IDE부터가 이를 사용해서 개발되기 시작했다. 비록 C/C++과 파스칼에서 모두 지원되긴 했지만 이 언어의 주 개발 및 지원 언어는 파스칼이었지 싶다. MS가 베이직을 좋아한다면, 볼랜드는 전통적으로 파스칼을 더 좋아하는 회사였다. (그러니까 훗날 델파이까지 만들었지)

지금은 세월이 세월이다 보니 소스가 완전히 풀려서 이이 프로젝트는 오픈소스 진영에서 관리되고 있다. 내 기억이 맞다면 DJGPP의 IDE인 Rhide가 이 Turbo Vision의 오픈소스 버전으로 개발되었다.
그리고 우리나라에서 PC 경진대회가 정보 올림피아드로 최초로 바뀌었던 1996년(13회), 대회의 채점 프로그램이 Turbo Vision 기반으로 개발되어 있던 걸 본인은 분명히 봤다.

2. 오늘날 윈도우용 네이티브 EXE/DLL이 만들어지는 출처는, 내 감으로는 비주얼 C++이 적게 잡아도 70% 이상, 그 뒤에 소수의 오픈소스 프로젝트용으로 gcc, 그리고 끝으로 델파이 정도가 고작인 것 같다. 볼랜드는 그 후로 다른 회사에 인수되면서 이름도 여러 번 바뀌고(InPrise, CodeGear, Embarcadero 등...;;) 우여곡절을 많이 겪었는데 걔네 입장에서는 옛날의 영광이 그리울 법도 할 것 같다.

3. BGI 라이브러리와 파워베이직--얘 역시 전신이 볼랜드 사의 터보 베이직이긴 했지만--의 그래픽 라이브러리는 이상하게도 VGA mode 13h를 지원하지 않아서 개인적으로 아쉬웠었다. (퀵베이직은 지원했는데...) 해상도가 너무 낮아서 한글· 한자 같은 문자를 찍는 데는 부적격이었지만 256색 덕분에 게임 만들 때는 필수이던 그래픽 모드이다. 그게 지원됐으면 그 당시 게임 만들기가 훨씬 더 수월했을 텐데 말이다.

Posted by 사무엘

2011/07/15 08:38 2011/07/15 08:38
, , ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/540

아래 코드를 실행하면 놀랍게도..
입력된 숫자에 대한 팩토리얼 값이 출력된다. 단, 플랫폼은 x86 한정으로..;;
(뭐, 컴퓨터가 돌아가는 원리를 아는 사람이라거나 맨날 기계어 코드 들여다보는 게 직업인 사람이라면 전혀 새삼스러운 일이 아니겠지만)

비주얼 C++뿐만이 아니라 도스용 DJGPP로도 프로그램이 잘 동작하는 걸 확인했다. 둘 다 IA32 아키텍처인 건 동일하니까 이는 당연한 귀결.

int main(int argc, char* argv[])
{
 BYTE instrs[]={
  0x55,
  0x8B,0xEC,
  0x83,0xEC,0x08,
  0xC7,0x45,0xFC,0x01,0x00,0x00,0x00,
  0x8B,0x45,0xFC,
  0x89,0x45,0xF8,
  0xEB,0x09,
  0x8B,0x4D,0xF8,
  0x83,0xC1,0x01,
  0x89,0x4D,0xF8,
  0x8B,0x55,0xF8,
  0x3B,0x55,0x08,
  0x7F,0x0C,
  0x8B,0x45,0xFC,
  0x0F,0xAF,0x45,0xF8,
  0x89,0x45,0xFC,
  0xEB,0xE3,
  0x8B,0x45,0xFC,
  0x8B,0xE5,
  0x5D,
  0xC3
 };

 PVOID pv = instrs;
 
int (*pfn)(int) = reinterpret_cast<int (*)(int)>(pv), y;
 while(1) {
  printf("? "); scanf("%d", &y); if(y<1) break;
  printf("%d\n", pfn(y));
 }
 return 0;
}


프로그래밍 언어의 인터프리터 내지 just-in-time 컴파일러를 만든다거나,
가상 기계 에뮬레이터를 만드는 것은 어렵지 않다.
결국 핵심이 뭐냐 하면 컴퓨터가 직통으로 실행하는 코드 자체를 실행 시간에 메모리에다 생성하는 건데,
함수 포인터가 가리키고 있는 게 바로 저런 것들이다.

물론, 위에서처럼 실행해야 할 코드가 완전히 고정돼 있는 경우라면
소스 코드에다 인라인 어셈블리를 집어넣으면 되겠지만, 그 코드는 데이터 영역에 들어가는 게 아니라 소스 코드(text) 영역에 그대로 포함되어 버리게 될 것이다.

위의 팩토리얼 함수는 물론 컴파일러가 생성해 준 코드를 복사한 것이다.
최적화를 안 한지라, 간단한 for 루프 하나밖에 없는 함수가 코드 길이가 꽤 길다.
최적화를 하고 나면 정상적인 함수 입출력 껍데기에 해당하는 코드조차도 거추장스러운지 생성되지 않아서
그걸 저렇게 따로 떼어내서 쓸 수가 없었다.

Posted by 사무엘

2011/07/08 08:06 2011/07/08 08:06
, ,
Response
No Trackback , 3 Comments
RSS :
http://moogi.new21.org/tc/rss/response/537

C/C++로 프로그램을 개발하는 과정에서 아주 난감해지는 경우 중 하나는, 바로 Debug 빌드와 Release 빌드의 실행 결과가 서로 다를 때이다. 개발 중이던 Debug 빌드 스냅샷에서는 잘만 돌아가는 프로그램이 정작 최적화된 Release 빌드에서는 이따금씩(항상도 아니고!) 에러가 난다면?

이런 버그는 문제를 찾아내려고 정작 디버거를 붙여서 실행할 때는 재연되지 않는 경우가 태반이어서 프로그래머를 더욱 애먹인다. 특히 복잡한 멀티스레드와 관련된 버그라면 그저 묵념뿐..;; 하지만 그런 특수한 경우가 아니라면, Debug와 Release의 실행 결과가 다른 이유는 본인의 경험상 거의 대부분이 초기화되지 않은 변수 때문이었다.

비주얼 C++은 Debug 빌드에서는 초기화되지 않은(공간 확보만 해 놓고 프로그램이 아직 건드리지는 않은) 메모리의 영역을 티가 나는 값으로 미리 표시도 해 놓고 아주 특수하게 취급해 준다. 메모리를 할당해도 좌우에 여분을 두고 좀 넉넉하게 할당하며, 때로는 그 넉넉한 여분 공간의 값이 바뀐 것을 감지하여(바뀌어서는 안 되는데) 배열 첨자 초과 같은 에러를 알려 주기도 한다. 프로그래머의 입장에서야 이건 꽤 유용한 기능이다.

그러나 Release 빌드에는 이런 거추장스러운 작업이 물론 전혀 없다. 그러니 메모리 범위를 초과한다거나, 읽어서는 안 되는 엉뚱한 주소의 메모리로부터 값을 읽거나, 올바른 영역이더라도 초기화되지 않은 쓰레기 값을 얻었을 때의 결과는 두 빌드가 서로 극과 극으로 달라질 수밖에 없다.

이렇게, 빌드 configuration에 따라 동작이 달라지는 코드는 두말 할 나위도 없이 결함이 들어있는 faulty 코드이다. 이런 코드에서 문제의 원인을 찾는 건 극도로 어려운 일이다. 서울에서 김 서방 찾기, 모래사장에서 바늘 찾기, 사격장에서 흘린 탄피 찾기가 따로 없다. ㅜㅜ 자기가 짠 코드에서 결함을 찾는 것도 어려워 죽겠는데 하물며 회사 같은 데서 남이 짠 faulty 코드를 인수인계 받았다면... -_-;;;

(본인이 다니던 모 병특 회사에서 본인의 직속 상사는 이렇게 말했다. “그런 코드를 짜는 건 프로그래밍을 하는 게 아니라 똥을 싸는 거다.” 공감한다. -_-)

C/C++은 물론 간단한 지역 변수에 대해서야 ‘이 변수를 초기화하지 않고 사용했습니다’ 같은 지적을 컴파일 시점에서 해 준다. 그러나 복잡한 포인터나 배열로 가면 일일이 그 용법이 올바른지 컴파일 시점에서 판단하지는 못한다. 그저 프로그래머가 조심해서 코드를 작성하는 수밖에 없다.

이와 관련된 본인의 경험을 소개하겠다.
꽤 옛날에 짜 놓은 비주얼 C++ MFC 기반 GUI 프로그램 소스의 내부에서, 핵심 알고리즘만 떼어내서 다른 콘솔 프로그램에다 붙여야 할 일이 있었다.
그 당시에는 나름 구조적으로 프로그램을 만든 것이지만, 지금 관점에서 모듈간의 cohesion은 여전히 개판오분전이었던지라 상당수의 코드를 리팩터링해야 했다.

그래서 코드를 붙였는데, 원래의 GUI 프로그램에서는 잘 돌아가던 코드가 새로운 프로젝트에서는 얼마 못 가서 뻗어 버렸다. Debug 빌드와 Release 빌드의 실행 결과가 다른 건 두말 할 나위도 없거니와, 심지어 같은 Release 빌드도 F5 디버거를 붙여서 실행하면 별 탈이 없는데 그냥 실행하면 뻗었다! 이건 스레드 쓰는 프로그램도 아닌데! 이거야말로 제일 골치 아픈 경우가 아닐 수 없었다.

Debug 빌드는 Release 빌드보다 워낙 느리게 돌아가고, Release 빌드도 디버거를 붙였을 때와 그렇지 않았을 때 성능이 살짝 달라진다. 그러니 앞에서 언급했듯이 스레드 관련 race condition은 영향을 받을 수 있다. 하지만 그런 것도 아니라면? 의심스러운 배열은 무조건 다 0으로 초기화하고, 혹시 내가 리팩터링을 하면서 실수를 하지는 않았는지 몇 번이나 꼼꼼이 살펴봤지만 문제는 눈에 띄지 않았다.

별 수 있나. printf 로그를 곳곳에다 박아 넣어서 의심스러운 부분을 추적한 뒤 다행히 문제를 찾아냈다.
게임 같은 리얼타임 시스템에서는, 심지어 디버그 로그 찍는 코드만 추가해도 버그가 쏙 숨바꼭질을 해 버리는 막장 중의 막장 경우도 있다만 내 프로그램은 그런 정도는 아니어서리..;;

사실은 기존 GUI 프로그램에서 돌아가던 코드에서부터 문제가 있었다.
배열을 선언했는데, 0~1번 인덱스에 접근할 일이 없어서

ptrData = new char[100];
ptrData-=2;

같은 잔머리를 굴려 줬던 것이다. 요런 짓을 옛날에 Deap 자료구조를 구현할 때도 했던 것 같다.
그러니 이 포인터로는 0과 1번 인덱스를 건드리지 않아야 하는데...
그런데 그것이 실제로 일어났습니다. ㄲㄲㄲㄲㄲ

그 허용되지 않는 메모리의 상태가 GUI 프로그램과 콘솔 프로그램, 심지어 같은 프로그램도 Debug와 Release, 디버거 붙이냐 안 붙이냐 여부에 따라 싹 달라져서 나를 골탕먹였던 것이다. 예전에는 수 년째 아무 탈 없이 잘 돌아가던 코드가 말이다.
저런 간단하고 고전적인 배열 첨자 초과 문제가 이런 결과를 야기할 줄 누가 알았을까?

C/C++은 내가 짠 코드를 내가 완전히 책임질 수 있고 컴퓨터 관점에서의 성능· 능률· 최적화가 중요한 해커나 컴덕후에게는 가히 환상적인 언어이다. 이보다 더 좋을 수가 없다. 예전에 내가 비유했듯, 세벌식이 기계 능률과 인체 공학적인 특징을 잘 살린 것만큼이나 이 언어는 고급 언어의 특성과 기계적인 특성을 꽤-_- 잘 절충했다.

그러나 언어의 구조적으로 가능한 무질서도가 너무 높은 것도 사실. C/C++가 까이는 면모 자체가 크게 (1) 언어 자체의 복잡도 내지 결함 그리고 (2) unmanaged 환경이라는 여건 자체라는 두 갈래로 나뉘는 양상을 보인다. 오늘날의 소프트웨어 시스템에서 프로그래밍 언어는 모름지기 수십, 수백만 줄의 프로젝트에서 살인적인 복잡도를 제어 가능해야 하고, 작성한 코드의 최소한의 품질과 안전성이 보장되어야 하며, 또 무엇보다도 빨리빨리 빌드가 돼야 하는데 C/C++은 영 한계를 보이기도 한다.

뭐, 그래도 이미 C/C++로 작성된 코드가 너-_-무 많고 그것도 다들 중요한 저수준 계층에 있다 보니, 이 언어가 쉽게 없어지지는 않을 것이고 특히 C++은 몰라도 C는 절대 안 없어지리라.. ㅋㅋ 프로그래밍 언어의 라틴어급.

C/C++과는 전혀 다른 언어이다만, 과거엔 QuickBasic도 IDE에서 돌리는 프로그램과, 실제로 컴파일-링크를 한 EXE의 실행 모습이 대동소이하게 달라서 프로그래머를 애먹이기도 했다. 물론 이건 C/C++에서의 Debug/Release와는 다른 양상 때문에 차이가 나는 경우이다.
결론은, 프로그램 작성하다가도 틈틈이 Release 형태로 최종 결과물을 확인하는 게 필요하다. ^^

Posted by 사무엘

2011/06/22 08:23 2011/06/22 08:23
,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/529

C/C++에는 ? : 라는 독특한 연산자가 있다. A ? B: C꼴로 표현되어 피연산자가 3개나 붙는 유일한 연산자이다.
이 연산자의 역할은 매우 단순하다. A가 참이면 연산자의 값은 B가 되고, 그렇지 않으면 C가 된다. 그래서 아예 if문의 역할을 간단히 대신할 수도 있으며, 콤마 연산자와 결합하면 어지간한 함수 호출마저도 한 연산식에다 박아 넣을 수 있다. 다만, 그게 너무 사악하다고 여겨졌는지-_-, C# 언어에는 콤마 연산자가 사라지고 콤마는 for 키워드 안에서만 제한적으로나 허용되지 싶다.

? : 는 &&, || 와 마찬가지로 C/C++에서 단축연산이 적용된다. A && B에서 A가 거짓이면 B는 실행이 전혀 되지 않고 전체 결과가 거짓이 되며, A || B에서 A가 참이면 B는 실행되지 않고 바로 전체 결과가 참이 된다. 그런 것처럼 ? :는 선택되지 않은 항에 대해서는 당연히 연산이 일어나지 않는다.

<날개셋> 한글 입력기는 짝퉁 C언어 문법 수식 해석기를 내장하고 있기 때문에, 이를 이용해 글쇠, 오토마타, 글자판 전환 글쇠 등에서 문자 입력 시스템의 자유도를 굉장히 높일 수 있다. 비록 튜링 완전한 수준은 못 돼도 말이다. 이때에도 ? : 연산자는 물론 매우 요긴하게 쓰인다.

? : 는 좌결합이 아니라 우결합이다. A ? B : C ? D : E는 (A?B:C) ? D : E가 아니라 A ? B : (C?D:E)로 결합한다. 그러므로 전자처럼 쓰려면 괄호를 넣어 줘야 한다.

? : 는 다른 연산 구문들을 포함하는 if문 대용처럼 쓰이는 만큼, 연산자의 우선순위가 상당히 낮다. 다른 평범한 연산자들이 다 결합한 뒤 나중에야 적용된다. 그게 합리적이다.
그러나 얘도 콤마와 대입 연산자보다는 순위가 높다. 그렇기 때문에 A = B ? C : D 라고 써 주면 알아서 A = (B?C:D)로 해석되어, A에는 B 조건의 충족 여부에 따라 C 아니면 D가 대입된다.

반대로, ? : 의 내부에 콤마 연산이나 대입 연산이 포함되어야 한다면 이들 연산은 무조건 괄호로 싸야 한다.

A ? (B=2): (C=5)
B에다가 괄호를 안 하면 = 가 ?와 :를 둘로 쪼개 버리는 효과가 나기 때문에 에러가 발생한다.
그리고 C에다가도 괄호를 생략할 수 없는데, 괄호를 안 하면 연산의 의미가 (A?(B=2):C)=5가 되어 버리기 때문이다. 우선순위의 특성상, =가 C항이 아니라 ? = 전체와 대응한다는 뜻 되겠다.

그리고 또 생각해 볼 것은, ? : 연산자의 값은 L-value가 될 수 있겠냐는 점이다. (대입 가능하겠냐)
<날개셋> 한글 입력기는 수식이 처음 도입된 3.0 이래로 지금까지 (조건 ? A:B)=100 과 같은 구문이 지원된 적은 없다. 그러나 이제 <날개셋> 6.0 이후의 다음 버전부터는 그게 가능해진다. 단, 2항과 3항 중 하나라도 변수에 연산자가 조금이라도 붙어서 A+2, -B 같은 형태가 되면 L-value 원칙이 깨지게 되는데, 그런 오류는 수식 입력 시점에서 프로그램이 자동으로 감지해 준다.

이게 지원되면 조건 ? (A=100): (B=100)보다야 구문을 더욱 간단하게 만들 수 있으니까 사용자의 입장에서 좋을 것이다. 더구나 콤마 연산자도 최후의 항의 변수 정보를 남겨 주기 때문에 (조건 ? (A=100,C): (B=50,D)) +=20 같은 복잡한 대입도 가능해진다. 저 식의 의미는 무엇일지 독자 여러분이 생각해 보기 바란다.

정작 이 연산자에서는 괄호가 필요하지 않다. 조건 ? A:B=100 이라고 하면 (조건 ? A:B)=100이 되며, 100 대입 연산은 3항의 B에만 연결되는 게 아니라 ? : 연산의 결과 전체에 걸린다. ? : 의 우선순위가 =보다 높기 때문에 =보다 먼저 계산되기 때문이다.

<날개셋> 한글 입력기로 복잡한 수식을 다뤄 본 분들은 이미 아시겠지만, 이 프로그램은 사용자가 입력한 수식을 어느 정도 자동으로 간소화를 한다. 상수 연산은 미리 계산을 해 버리며, 100/0나 2=A 같은 뻔한 에러는 미리 지적해 준다. 그리고 우선순위 규정상 굳이 칠 필요가 없는 괄호도 알아서 제거를 해 버린다.

(A+B)-C는 A+B-C로 바뀌며, 이와 비슷한 맥락으로 (조건 ? A:B)=100도 그냥 조건 ? A:B=100으로 바꾼다. 이건 프로그램의 오동작이 아니므로 놀라지 말고 수식을 사용하면 된다.

그런데 비주얼 C++ 같은 요즘의 C/C++ 컴파일러들은 ? :를 본인이 생각한 것처럼 취급하지 않는 것 같다.
A==100 ?B:C=400 라고 하면 =400은 3항의 C에만 붙지 B에는 붙지 않는다. (A==100 ? B:C)=400이라고 해 줘야 한다.
또한 ?와 : 사이에 있는 2항은 사이에 대입이나 콤마 같은 연산자(우선순위가 ? :보다 한참 더 낮은!)가 괄호 없이 연결되어 있어도 알아서 2항의 일부라고 인식해 주는 듯.
물론, 그렇다고 해서 A=조건 ? 2항: 3항 같은 문장이 있으면 A=까지 조건으로 끌어들이지는 않는다.

이런 세세한 동작 방식에 대해서 정보를 얻고 싶어서 비주얼 C++ 도움말을 찾아봐도, ? :는 대입 연산자보다 우선순위가 높다던가, 2항과 3항의 타입이 서로 다를 때 연산자 값이 정해지는 원칙 같은 원론적인 말밖에 없다. 그 말대로라면 무조건 내 프로그램처럼 괄호를 써야만 할 텐데 말이다.

그 간단한 ? : 연산자에도 의외로 복잡한 사연이 있다는 걸 알 수 있다.
어쨌든 내 프로그램은 ? : 안에 대입이나 콤마 연산을 포함시키려면 무조건 괄호를 써야만 하는 구조가 앞으로도 유지될 것이다.

Posted by 사무엘

2011/06/05 19:20 2011/06/05 19:20
, ,
Response
No Trackback , 4 Comments
RSS :
http://moogi.new21.org/tc/rss/response/521

파이썬 언어

요즘 개인적으로 파이썬을 틈틈이 공부하고 있는데, 나름 재미있다. 대략 20세기 말쯤에 우리나라에 파이썬이 얼리어답터 선구자들에 의해 처음으로 대대적으로 소개됐을 때는, Python의 한글 표기조차도 통일이 안 돼 있었다고 하니 참으로 격세지감이다. 본인은 처음부터 일관되게 파이썬이라고만 들었다.

파이썬이라는 언어가 있다는 걸 본인이 안 건 굉장히 오래 됐다. 거의 2001~2002년 사이인데, 당시 세벌식 사랑 모임에서 '컴바치'라는 필명을 쓰던 송 시중 님과 얘기를 나누다가 파이썬에 대해 처음으로 들었다. 이분, 연락이 끊어진 지는 굉장히 오래 됐는데, 지금은 뭘 하고 계시는지 모르겠다.

그 후 본인은 학교 후배로부터도 파이썬을 좀 공부하는 게 어떻냐는 권유를 몇 차례 받았다. 하지만 오로지 C++ 만능주의에 <날개셋> 한글 입력기 개발에만 정신이 팔려 있던 본인은, “난 비주얼 C++만 있으면 컴퓨터를 내가 원하는 대로 얼마든지 부려 쓸 수 있는데, 그거 또 배워서 뭐 함?” 식으로 별 흥미를 느끼지 못했다. 난 전산학 전공자치고는 컴퓨터 다루는 형태가 아주 기괴하다. -_-;;

그로부터도 또 수 년이 지나고, 무려 대학원에 가서야 본인은 드디어 파이썬을 다시 대면하게 됐다. 파이썬이 말뭉치 같은 대용량 텍스트 데이터를 다루는 도구로서, 전산 비전공자도 쉽게 배울 수 있는 언어로 즐겨 쓰이고 있었던 것이다.

나는 문과 기반이 부족하니 그런 걸 주변 선배들로부터 보충받고, 반대로 전산학 기반이 아주 탄탄하기 때문에 그런 걸 전수해 주는 쪽으로 협업 구도가 자연스럽게 형성되었다. 파이썬 좀 가르쳐 달라는 요청이 있기도 했으니, 본인은 남을 가르치기 위해서 내 자신부터 파이썬을 공부하게 됐다.

한동안 공부해 본 소감은... 파이썬은 꽤 재미있는 언어이다!
type이 runtime 때 동적으로 결정되고 무척 유동적이라는 것은 C++ 특유의 그 경직된 사고방식으로부터 해방감을 느끼게 해 줬다.

{ } 일색인 C/C++, 자바, C# 같은 언어하고만 놀다가...
들여쓰기가 필수 조건이고 for/while/def :로 끝난다는 언어를 접하니 느낌이 새롭다. 좀 베이직과 비슷하다는 생각도 든다. 물론 그렇다고 행번호+GOTO 스파게티 같은 건 전혀 없지만.

다중 대입 기능이라든가 리스트의 slicing 연산은 무척 편리하고 좋았다.
여타 언어였다면 또 임시 변수를 동원한다거나, 번거로운 개체 생성과 반복문이 필요했을 것이다.
C/C++, 자바, C#의 for문은 while문을 형태만 바꾼 것과 완전히 동치이지만, 파이썬의 for 문은 철저하게 복합 자료형의 각 원소를 순회하는 기능에 맞춰져 있다. for문의 설계 철학은 C스타일 언어와 베이직/파스칼 스타일 언어, 그리고 파이썬도 살짝 차이가 있는 것 같다.

언어와 내 사고방식이 완전히 일심동체가 되기 위해서는,
- 리스트 같은 복합 자료형이 내부적으로 구현되는 실제 자료 구조는 무엇이며 시간 복잡도가 얼마나 되는가? 메모리 재할당 비용이 얼마나 되는가?
- 대용량의 복합 자료형을 만들어서 복제하거나 함수 인자로 전달했을 때 shallow copy가 일어나는가, deep copy가 일어나는가?

이런 식의 디테일을 알 필요가 있다.
이것도 몇 번 튜토리얼을 읽고 예제 코드를 짜면서 시행 착오를 겪어 보니 그리 어렵지 않게 이해가 됐다.
문자열과 튜플은 새로운 값의 생성과 대입/재대입만 가능하지, 이미 만들어진 값의 변경은 허용되지 않는다는 대목에서 '아하~!' 소리가 절로 나왔다.
뭐, 문자열도 필요한 경우엔 mutable array 형태로 내부 조작을 할 수도 있다.

파이썬으로 윈도우 API도 호출하고 온갖 희한한 라이브러리를 동원해서 각종 컴퓨터 자동화 작업을 수행하고 별 걸 다 하는 친구도 있는데, 본인은 그 정도 수준은 안 된다. 그래도 이 정도만으로도 좋은 경험이다.

내게 파이썬을 권하던 후배 녀석이 이제는 HTML 공부도 좀 하라고 권한다. 이제는 플래시나 ActiveX 없이도 웹 표준 자체만으로도 별 걸 다 만드니, 훅킹을 한다거나 컴퓨터의 임의의 파일이나 레지스트리를 건드려야 하지 않는 이상 ActiveX의 필요성은 갈수록 없어지고 있다. 웹이 처음에는 그림+글+하이퍼텍스트로 된 문서일 뿐이었는데 지금은 그 자체가 거의 플랫폼처럼 됐다.

Posted by 사무엘

2011/05/25 08:18 2011/05/25 08:18
,
Response
No Trackback , 9 Comments
RSS :
http://moogi.new21.org/tc/rss/response/516

컴퓨터는 배열로 표현된 직사각형 형태의 데이터를 처리하는 걸 좋아하며, 이는 그래픽에서도 예외가 아니다.
그러나 사람이 생각하는 개념을 그래픽 개체의 형태로 표현하다 보면 직사각형이 아닌 임의의 모양의 그래픽을 찍어야 할 일이 생긴다.
게임에서는 스프라이트가 좋은 예이고, 굳이 게임이 아니더라도 GUI 환경에서는 아이콘이라든가 심지어 customized 마우스 포인터도 그런 부류에 속하는 그래픽이다.

이런 그래픽은 결국 큰 직사각형 안에서 투명색을 제외한 나머지 색상을 찍는 방법으로 처리하는데, 그 구체적인 테크닉은 역사적으로 아래와 같은 세 양상을 거치며 바뀌어 왔다.

1. 모노크롬이나 그에 준하는 저색상: 비트 연산

그림을 두 장 준비한다. 그리고 그 두 장을 화면에다 그냥 copy만 하는 게 아니라, 화면에 이미 있는 픽셀과 비트 연산을 하여 그 결과를 찍는다. 이것을 raster operation이라고 하는데, 비트 연산은 CPU-friendly한 작업이기 때문에 컴퓨터가 나름 빠르게 수행할 수 있다.

준비해야 하는 그림은,
찍어야 할 내용이 그려져 있고 배경은 '검은색'(0)으로 처리되어 있는 '원래 비트맵'과,
원래 비트맵하고는 정반대로 배경은 무조건 '흰색'(1)이고 내가 차지하는 스프라이트 영역은 '검은색'(0)으로 처리되어 있는 '마스크 비트맵' 이렇게 둘이다. 마스크 비트맵은 1 아니면 0만 있는 모노크롬이다.
(따라서 '원래 비트맵'만으로는 검은색이 배경인지 아니면 스프라이트가 실제로 차지하는 검은색인지 알 수 없다.)

화면에다가는 먼저 마스크 비트맵을 AND 연산으로 그린다. 원래 화면에 있던 픽셀이 X라면, 마스크에서 배경으로 처리된 픽셀은 X AND 1이므로 X가 그대로 남고, 0이면 0이 되어 검은색이 된다.
즉, 마스크 비트맵에 대한 AND 연산은, 스프라이트가 칠해져야 할 영역만 시꺼멓게 만드는 효과를 낸다.

그리고 다음으로 이 자리에다가 원래 비트맵을 XOR 연산으로 그린다.
0 XOR X = X이므로, 이 연산을 수행해 주면 화면이 0으로(특히 마스크 비트맵 AND 연산으로 인해 0이 된) 시꺼먼 곳은 원래 비트맵이 그대로 그려지고, 원래 비트맵이 0인 배경은 아무 변화가 생기지 않는다.

사용자 삽입 이미지

그림의 출처는 위키백과.
이로써 스프라이트가 멋있게 그려졌다.
도스용 게임 중에 <위험한 데이브>는 이런 초보적인 XOR 방식으로 스프라이트를 찍었기 때문에, 검은 배경이 아니라 두 스프라이트가 겹치면 화면에 잔상이 남곤 했다.

옛날 윈도우 9x 시절에.. 컴퓨터 메모리가 많이 부족해서 하드디스크 스와핑/thrashing이 일어나고 프로그램의 각종 아이콘들이 그려지는 게 눈에 보일 때는... 아이콘이 차지하는 영역이 먼저 시꺼매지거나 반대로 잠깐 하얗게 번쩍이는 걸 볼 수 있었다. 흠, 프로토스 건물도 소환이 끝났을 때 실루엣이 허옇게 번쩍이다가 원래 형태가 드러나는데...;; raster 연산을 더블버퍼링 없이 화면에다 바로 그리다 보니, 컴퓨터 속도가 느려졌을 때 그 중간 과정이 눈에 띄는 것이다.

검정에다가 원래 비트맵의 색을 합성할 때는 이론적으로 OR을 써도 되는데 XOR이 의도적으로 쓰이고 있다.
이는 XOR이 유용하기 때문이다. XOR 1은 비트를 반전시켜 준다는 특성상, XOR 연산으로 그린 그림은 거기에다 XOR을 한번 더 해 주면, 다른 곳에 영향을 주지 않고 자기가 차지하고 있던 영역에서만 완전히 지워진다.

XOR 연산은 컴퓨터의 입장에서는 매우 부담이 가볍기 때문에, 마우스 선택 영역을 나타내는 점선 사각형이라든가 창 크기를 조절하는 작대기처럼 수시로 업데이트를 해 줘야 하는 비주얼 효과를 나타낼 때 즐겨 쓰인다.
아니, 텍스트 블록이라든가 깜빡이는 커서(캐럿)조차도 반전 사각형이니까 XOR이다.

마우스 포인터도 XOR 연산이다. 텍스트 입력란을 뜻하는 I자(beam) 모양의 마우스 포인터는 검은색이 아니라 배경색에 대한 반전색이다. 마스크 비트맵 값을 0이 아닌 1로 둬서 배경을 지우지 않은 상태에서 XOR 비트맵도 1로 해 주면 배경색이 반전되는 효과가 난다. ^^;;

XOR 연산은 디지털 컴퓨터가 존재하는 한 그래픽에서 언제까지나 없어지지 않고 쓰일 방식이긴 하지만... 오늘날은 다소 촌스러운(?) 것으로 간주되고 있기도 한다. GPU님이 계시니 화면 비주얼을 굳이 CPU 친화적인 방법만 고집할 필요는 없는 듯. 그래서 요즘은 뭔가 선택 영역을 나타낼 때 알파 블렌딩을 동원하여 다 옅은 파란 배경 + 더블버퍼링으로 대체되는 추세이다. 화면 전체의 DC를 얻어와서 XOR 연산을 시키는 건 Aero 환경에서는 오히려 성능을 더욱 떨어뜨리는 짓이기도 하니 말이다.

2. 모노크롬 이상 16~256색 사이: 컬러 키(color key)

그 후 컴퓨터의 그래픽 카드의 성능이 향상되면서, 256색 시대가 열렸다. 256색은 팔레트 조작이라는 과도기적인 괴악한 개념을 도입한 걸로도 유명하다.
색깔이 적당히 많아졌기 때문에, 비트맵에서 256색 중 하나만 투명색으로 예약하여 쓰지 않고 나머지 색은 그대로 찍게 하는 방식이 유리하다. 마스크 비트맵 따위를 번거롭게 구비할 필요가 없다. 또한 256색은 RGB 값이 아니라 인덱스 기반 컬러를 쓰기 때문에, xor 반전 연산이 어차피 그렇게 큰 의미를 지니지도 않는다. (실제 색깔값이 반전되는 게 아니라 팔레트 인덱스 번호가 반전되기 때문)

256색 전용으로 유명한 gif 그래픽 파일이 이런 컬러 키를 지정하여 투명색을 지정할 수 있다.
윈도우 API에도 비트맵이나 아이콘의 (0, 0) 위치 픽셀을 투명색으로 간주하고 그려 주는 함수가 있으며, SetLayeredWindowAttributes 함수는 컬러 키를 지정하여 해당색을 투명하게 처리함으로써 non-rectangular 윈도우를 만드는 효과를 내어 준다. region을 만들지 않고도 동일한 일을 할 수 있다는 뜻이다.

3. 트루컬러: 알파 채널

투명색 처리의 최종 완전체는 바로 알파 채널이다. 이건 과거의 픽셀 raster operation과는 차원이 다르며, 컴퓨터가 빨라진 정도를 넘어 그래픽 가속을 위한 별도의 GPU까지 등장하면서 가능해진 궁극의 기술이다.
매 픽셀에다가 이분법적인 투명 여부가 아니라, 이 픽셀이 배경과 얼마나 짙게 오버랩될지 반투명 등급 자체가 추가로 들어간다. RGB에 이어 A까지, 가히 색깔의 4차원화인데, 기계 입장에서는 한 픽셀당 딱 정확히 32비트이니 처리하기에는 다행히 좋다.

256색을 초월한 천연색 그래픽에는 워낙 많은 개수의 색상이 쓰이기 때문에.. 그 중 딱 한 색깔에다가만 컬러 키를 부여하는 게 무의미하다. 그리고 마치 글꼴에도 안티앨리어싱을 하듯, 스프라이트도 경계가 배경색과 부드럽게 융합해야 트루컬러의 진정한 의미가 살아난다. 그래서 알파 채널이 필요한 것이다.

윈도우 98에서 알파 채널을 적용한 비트맵 찍기라든가 그러데이션을 한번에 처리하는 API가 처음으로 추가됐다. 프로그램의 제목 표시줄에 그러데이션 효과가 윈도우 98에서 처음 추가되었는데, 바로 이 API를 쓴 것이다.
그리고 윈도우 XP에서는 알파 채널이 적용된 확장 아이콘이 처음으로 도입되었고, GDI+는 그리기 기능에 전반적으로 알파 채널을 염두에 두고 설계되었다. 하지만 GDI의 기본적인 벡터 드로잉 함수는 그런 새로운 기술로부터 소외되어 있으니 안타까울 뿐.

윈도우 비스타는 48*48도 모자라서 아예 256*256 크기의 아이콘을 지원한다. XP 때부터 이제 아이콘 하나가 2~3만 바이트에 달하는 시대가 됐는데(윈도우 3.1 시절에는 1~2천 바이트.. -_-), 전통적인 ico는 bmp와 같은 '무압축 포맷'인지라 256*256 크기의 32비트 픽셀을 저장했다간 크기를 감당할 수가 없기 때문에, ico 포맷은 내부적으로 png 파일도 포함할 수 있게 구조가 확장되었다.
gif를 대체하는 새로운 이미지 포맷인 png는 알파 채널을 지원한다. 그 자그마한 아이콘 하나도 전문 그래픽 디자이너가 포토샵으로 만들어야 하는 시대가 도래한 지 오래이다.

윈도우 내부적으로는 아이콘과 마우스 포인터 파일은 거의 동일한 포맷으로 간주된다. 아이콘은 이미지 이미지 비트맵과 마스크 비트맵 이렇게 둘 들어있는 형태이며, 마우스 커서는 거기에다 센터 위치가 추가되고.. 애니메이션 포인터는 gif스럽게 프레임이 더 추가되겠구나.
알파 채널이 등장하면서 마스크 비트맵은 존재 가치가 상당수 퇴색하긴 했으나, 오늘날에도 고전 테마(XP의 Luna, 비스타의 Aero 따위가 없는)에서 아이콘을 찍을 때라든가 disabled 상태 같은 변형 상태를 찍을 때 참고 정보로 쓰이기 때문에, 완전히 필요가 없어진 것은 아니다.

요컨대 오늘날은 기술 발전의 정도에 따라 최소한 세 가지 형태의 투명색 표현 기법이 쓰이고 있는 셈이다. 흥미로운 사실이다.

Posted by 사무엘

2011/01/24 07:35 2011/01/24 07:35
, , ,
Response
No Trackback , 7 Comments
RSS :
http://moogi.new21.org/tc/rss/response/454

« Previous : 1 : ... 18 : 19 : 20 : 21 : 22 : 23 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          

Site Stats

Total hits:
2860929
Today:
605
Yesterday:
1286