« Previous : 1 : ... 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : ... 31 : Next »

프로그래밍 잡설

1. 닷넷 기반 프로그램의 특징:

- 뜨는 데 시간이 좀 오래 걸린다.
- 파일 내부를 들여다보면 전통적인 네이티브 프로그램처럼 kernel32, user32, gdi32 따위가 아니라, mscoree.dll에 대한 Dependency만 있다.
- 생성하는 GUI 윈도우들의 클래스를 보면 WindowsForm10 이런 명칭으로 시작한다.
- 같이 들어있는 DLL들이 '뭐.뭐' 이런 식으로 대소문자가 섞이고 중간에 마침표도 있는 등, 이례적으로 이름이 긴 경향이 있다. 네이티브 EXE/DLL은 그런 식으로 작명되는 경우가, 금지되거나 불가능한 건 절대 아님에도 불구하고, 거의 없다. 유닉스 내지 심지어 도스 시절 8.3 영향을 받은 짧고 암호 같은 영어 알파벳 조합이 아직까지 대세.

유명한 닷넷 프로그램으로는 MS Keyboard Layout Creator, Paint .NET이 있다. 비록 닷넷 기반으로 비주얼 베이직.NET과 C++ managed extension 같은 언어도 있긴 하지만, 그래도 90%이상의 여건에서는 닷넷이 곧 C#이나 마찬가지이다.

게임 자체는 모르겠지만, 최소한 게임과 관련된 툴 정도는 C#으로 만드는 게 충분히 승산이 있는 단계에 이른 것 같다. 스타크래프트의 StarEdit처럼 고객이 사용하는 툴이든, 게임 개발사 내부에서 디자이너나 기획자가 쓰는 툴이든 말이다. C#은 일종의 가상 기계 프레임워크 기반이면서도 로컬 환경 역시 적당하게 잘 공략한 것 같다. 이제 MFC는 덩치가 커져도 너무 커졌고, C#은 빌드 속도 같은 생산성 면에서 C++을 압도적으로 능가한다.

게임 클라이언트에 이어 게임 서버까지 C#으로 만들어 돌리는 날이 과연 올지는 모르겠다. 컴퓨터의 성능이 계속 향상되니까 괜찮을 거라는 말이 있지만, 그래도 과거에 C/C++은 어셈블리와 일대일 대응하는 최소한 네이티브 코드 생성 언어이지 않았던가.
다만, 아직은 C# 프로그램이 네이티브에 비해 느린 건 둘째치고라도, 앞서 말했듯이 좀 무겁다는 인상이 짙게 느껴진다. (뜨는 데 걸리는 시간) 이게 좀 개선됐으면 좋겠다. 듣자하니, MS는 내부적으로는 C# 코드를 산뜻한 네이티브 코드로 빌드해 주는 컴파일러를 보유하고 있다는데..;;

2.
본인, 전공이 전공이다 보니 소위 '국어 정보 처리' 분야의 프로그램들을 좀 접했다. 형태소 분석, 말뭉치 검색 등.
비주얼 C++ + MFC로 만들어진 게 다수이지만 2005년 이후부터는 C#을 쓴 것도 심심찮게 보인다. 다만, '깜짝새'라고 유명한 프로그램이 있는데, 얘는 이례적으로 델파이로 개발됐다.

이런 프로그램들은 그 특성상, 결과 데이터를 마치 스프레드 시트처럼 row-column 형태의 출력하는 경우가 많다. 그런데 순수하게 처리를 하는 비용뿐만이 아니라, 처리가 끝난 결과 데이터를 해당 리스트 컨트롤에다 등록하는 데 걸리는 시간도 만만찮아서 본인은 그게 불만이다. 결과 출력하느라 리스트 컨트롤의 스크롤바가 쫘르륵~~ 변하는 모습을 보고 있으면 좀 민망하다. 불필요한 화면 refresh가 수천, 수만 회 발생하고 있다는 뜻이지 않은가?

대용량의 데이터를 그런 형태로 출력할 때는, owner-draw라든가 virtual list control 테크닉을 써서, 결과 데이터를 일일이 리스트 컨트롤로 복사하는 게 아니라, 그때 그때 출력을 내가 직접 하도록 해야 한다. 이렇게만 하면 프로그램의 체감 동작 속도가 월등히 빨라지며 메모리도 크게 아낄 수 있다.
도스 시절이었다면 리스트 컨트롤 같은 컴포넌트라는 개념 자체가 없었을 터이니 이런 비효율 자체가 존재할 여지가 없었을 것이다. 물론, 소프트웨어의 재활용성면에서 도스는 어차피 빵점인 열악한 환경이니 도스 시절이 마냥 좋다는 건 아니다.

저런 프로그램들이 어떤 여건 속에서 개발되었는지 잘은 모르겠다. 허나, 열악한 자금과 시간에 쫓기면서 공밀레 공밀레 하면서 만들어진 프로그램이라면, 개발자가 아무리 날고 기는 천재 프로그래머라고 해도 답이 없다. 품질을 보증할 수 없고, 이런 자그마한 곳에서의 사용자 배려 따위는 절대로 기대할 수 없다. 이는 개인의 프로그래밍 실력과는 하등 관계 없는 문제이다.

그 반면에 <날개셋> 한글 입력기가 가히 변태적인 수준의 최적화를 자랑하며 개발되고 있는 이유는 시간과 돈에 전혀 구애받지 않고 전적으로 개인의 자아 실현을 위해 만들어지는 프로그램이기 때문이다. -_-;; 언제까지나 그런 태도로 프로그램을 만들 수는 없으니까 그게 문제지만.
이런 문제를 이쪽에 계시는 교수님들도 인지는 하고 있지만, 우리나라 IT 인프라에 전반적으로 딱히 답이 안 보이는 문제이니 어쩔 수 없다.

3.
C/C++ 부류의 type 시스템은 액세스(MS Access)와 비슷하고,
파이썬 부류의 type 시스템은 엑셀(MS Excel)과 비슷하다. 진짜 딱 대응하는 것 같다.

스프레드 시트인 엑셀은 아무 셀에 아무 타입의 데이터나 바로 집어넣을 수 있으며, 그러면 그 형태를 엑셀이 알아서 인식해서 출력해 준다. 날짜는 날짜처럼, 문자열은 문자열처럼, 숫자는 숫자처럼 오른쪽 정렬을 해서.
그러나 데이터베이스 프로그램인 엑세스는 테이블을 설계할 때 모든 애트리뷰트와 각 애트리뷰트에 들어갈 수 있는 값의 타입을 지정해야 하며, 딱 그 값만 넣을 수 있다. 문자열은 길이 제한까지도 생각해야 한다. 정말 딱딱하고 까다롭다.

엑셀은 셀의 값들에 서식도 자유롭게 지정할 수 있고 Undo도 얼마든지 가능하다. 엑세스는 그런 게 없으며, 테이블을 수정한 게 파일에도 바로 반영된다.

그러나 수십, 수백만 개에 달하는 데이터를 검색하고 한꺼번에 고치고, 테이블 간의 관계를 분석하는 동작에서 엑셀과 엑세스의 효율은...;; 더 설명이 필요하지 않을 것이다.

그럼에도 불구하고 엑세스 급의 전문적인 성능이 필요한 경우는 매우 드물다. 일반 사용자들은 어지간한 중소 규모의 데이터나 다룰 것이고 이때는 친근한 엑셀이 대부분의 경우 훨씬 더 도움이 될 것이다.

4.
PC 파워 유저라면, 윈도우용 EXE 파일에는 리소스라는 별도의 데이터 섹션이 있다는 걸 알 것이다. 윈도우용 EXE는 이례적으로 자체 아이콘을 갖춘 파일 포맷인데, 그것도 바로 리소스라는 형태로 들어있다. 운영체제는 EXE/DLL의 리소스를 조작하는 API를 제공하며, 이를 이용하면 프로그램의 메뉴, 메시지 문자열을 고쳐서 허접하게나마 프로그램을 한글화(자국어화)할 수도 있다. 물론, 모든 프로그램에 그런 테크닉이 통하는 건 아니지만.

이 일을 프로그래밍을 통해서 하려면 BeginUpdateResource, UpdateResource, EndUpdateResource라는 함수를 쓰면 된다. 다만, 윈도우 9x는 이 기능을 지원하지 않았으며 그건 NT에서만 지원됐다. 그런 기능을 어차피 일반 사용자가 쓸 일은 없었을 테니까.
그런데 신기하게도 그 당시 윈도우 9x에서 실행된 비주얼 C++ 6은, 32비트 EXE/DLL의 리소스를 고칠 수는 없었던 반면, 16비트 EXE/DLL의 리소스를 고쳐서 저장할 수는 있었다.

윈도우 API를 쓴 건지, 아니면 16비트 바이너리는 비주얼 C++의 자체 기능으로 파일을 건드렸는지는 잘 모르겠다. 다만, 16비트 바이너리와 32비트 바이너리는 리소스를 저장하는 방식이 상당히 다르기 때문에 아마 자체 기능이 아니었겠나 싶다. 근본적으로 32비트 바이너리는 wide character 유니코드를 사용하지만 16비트 바이너리는 그렇지 않다. 그래서 과거에 윈도우 3.1에다가 Win32s를 설치하면 각종 시스템 DLL뿐만이 아니라 유니코드 변환 테이블인 NLS 파일들도 잔뜩 설치됐던 것이다.

Posted by 사무엘

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

오늘날, 어떤 데이터(개념상 Document라고 불리는)를 메모리에 완전히 읽어들여서 사용자가 그 데이터를 편집할 수 있는 업무용 프로그램에는... 거의 필수로 undo 기능이 있다.
이건 우리가 잘 실감을 못 해서 그렇지 사용자에게 심리적으로 굉장한 안정감을 주는 편리한 기능이다. 뭘 잘못해서 망쳐 놓더라도, '미리 저장 -> 지금 문서를 저장 안 하고 예전 문서를 다시 불러오기' 같은 뻘짓을 안 해도 Ctrl+Z만 누르면 만사 OK.

소프트웨어 GUI 가이드라인 교과서를 보면, 소프트웨어는 사용자에게 '용서'(forgiveness)라는 덕목을 발휘해야 한다는 말이 나온다. 사용자가 아무리 바보짓을 하더라도 이를 최대한 추스리고 수습하고 원상복귀 할 수 있어야 한다는 뜻.
컴퓨터 프로그램은 기독교의 하나님 같은 존재가 아니다. “자유 의지가 있으니, 하늘나라든 지옥이든 선택에 따른 책임도 전적으로 네 몫이다” 주의가 아니다. 그러니 인간의 삶에도 Undo가 있으면 참 좋을 텐데 현실은 그렇지 못하니 참으로 안습이다. 오히려 '말은 하고 못 줍는다', '엎질러진 물', '소 잃고 외양간 고친다' 같은 냉정한 속담만이 있을 뿐이다.

잡설이 길어졌다만,
역사적으로 Undo라는 개념이 허접하게나마 가장 일찍부터 존재한 분야는 그래픽 프로그램이었다.
걔네들은 원래부터 문화가 좀 독특해서 마우스의 비중이 매우 높으며, 우클릭이 Context menu의 의미로 쓰이지도 않을 정도이다.
그리고 근본적으로 마우스라는 게 키보드보다 실수를 훨씬 더 하기 쉬운 입력 장비이고, 한 번의 동작으로 수백· 수천 개의 픽셀이 한꺼번이 바뀔 수 있기 때문에 Undo가 없으면 안 된다.

문득 든 생각: 그래픽 프로그램을 이용해서 마우스로 Freehand drawing을 하는 도중에 bksp 키를 누르면.. 직전의 수 픽셀 단위로 곡선을 철회하는 기능이 있으면 좋을 것 같다. 정교한 도트 노가다 할 때 유용할 것 같다. 보통 Ctrl+Z 누르면 그렸던 선 전체가 한 방에 날아가 버리잖아?

물론 Undo라는 건 그렇게 쉽게 구현할 수 있는 기능이 아니며 메모리 오버헤드가 크다.
더구나, 과거에 Undo 기능이 있던 프로그램은 딱 한 단계밖에 취소가 되지 않았었다. Ctrl+Z를 누르면 직전 작업을 취소했다가, 다시 살렸다가 하기만을 반복할 뿐이었다. (메모장.. 정확히 말하면 윈도우 운영체제의 에디트 컨트롤도 딱 그 수준의 1단계 Undo를 지원한다.)
수십, 수백 단계의 작업을 고스란히 취소하고 취소 내역을 다시 철회(redo)까지 하는 command history 수준의 multi-level undo 기능은 1990년대까지만 해도 MS 워드 같은 소수의 상업용 대형 프로그램에서나 볼 수 있었다.

이런 프로그램은 Document의 내용을 변형하는 모든 명령들이 체계적으로 분류가 돼 있다. 그래서 편집 메뉴를 열어 보면 단순히 '실행 취소 / 재실행'이라고만 돼 있는 게 아니라 '삭제 취소 / 취소된 자동 완성 재실행'처럼, 무슨 명령이 직전에 취소되었고 무엇을 재실행할지 명령의 이름까지 메뉴에 친절하게 표시돼 있기도 한다.
그 반면, Undo/redo를 염두에 두지 않고 Document를 고치는 코드가 제멋대로 섞여 있던 프로그램에다가 어느덧 갑자기 multi-level Undo/redo 기능을 최초로 추가할 일이 생겼다면 아마 십중팔구 코드를 다 갈아엎는 대공사를 해야 할 것이다.

컴퓨터의 성능이 열악하던 도스 시절엔, Undo와 Redo가 모두 존재하는 프로그램은 매우 드물었다.
아래아한글 1.x는 좀 특이한 경우인데, 줄 끝까지 지우기· 단어 지우기 같은 몇몇 지우기 명령으로 인해 지워진 텍스트만을 1회에 한해 되살리는 Undo 기능이 있었다.
그 후 아래아한글 2.0에서 97은 그 Undo의 단계가 3회로 늘었을 뿐이었다. 내 기억이 맞다면, 이 기능은 최근 3회의 주요 지우기 단축키(메뉴에 등재되지 않은)에 의해 지워졌던 텍스트 중 하나를 골라서 커서가 있는 곳에다 삽입해 주는 기능에 불과했다. 원래 있던 위치에 되돌려 놓는 것도 아니고... -_-

Ctrl+X(오려두기)야 본문이 클립보드에 고스란히 들어가 있으니 별도의 Undo 버퍼에다 저장할 필요가 없고,
Ctrl+E(지우기)로 지워진 텍스트는 의도적으로 되살리기가 전혀 되지 않는다고 도움말에 친절하게 안내까지 돼 있었다. ^^;;
그것 말고 문서나 표 레이아웃을 잘못 건드려서 망쳤다거나 하는 더 중요한 기능에 Undo 따위는.. “Undo 뭥미? 그거 먹는겅미? 우걱우걱...”이었다. 그냥 이전 문서를 새로 불러오는 수밖에..
이런 불편한 프로그램을 옛날 사람들은 어떻게 쓰고 지냈을까?

그래서 아래아한글 2002는 256단계 undo가 지원된다고 잔뜩 광고를 하고 다녔었다. MS 제품들은 진작부터 지원한 기능인데도 말이다. 하긴, 그것 말고도 글자 크기 제한이 드디어 없어지고 글자색 제한이 없어진 것도 개인적으로 무척 마음에 들긴 했다. better late than never이다.

<날개셋> 한글 입력기의 편집기 프로그램은 1.x와 2.x 시절에는 Undo 비슷한 기능도 전혀 없었다. 3.0에 가서야 32단계의 multi-level undo가 추가되기는 했으나... 글자 하나, 한글 낱자 하나 입력되는 모든 단계가 histroy에 기록된지라 실용성이 시원찮았다.
그것이 지금의 형태로 개선되 것이 4.2 버전부터이다. 연속된 에디팅 동작뿐만이 아니라 불연속적인 에디팅 동작을 한 history로 통합하는 기능까지 추가되어, 여러 블록을 동시에 삭제한 것이나 Replace All 명령을 내린 것도 한 번에 취소가 가능해졌다.

사실 <날개셋> 편집기의 에디팅 엔진은 아직 좀 효율적이지 못한 구석이 있다. Undo/redo 명령을 내리면 그 부분이 아무리 사소하더라도 문서 전체의 레이아웃을 싹 다시 하고, 화면 전체를 새로 그린다. 그렇기 때문에 수~수십 MB짜리 텍스트를 연 뒤에 Ctrl+Z를 꾹 누르고 있기가 겁난다. 본인은 이 프로그램을 만든 사람이고 프로그램의 내부 디테일이 어떤지를 잘 알기 때문에 그러기가 더욱 꺼려진다.

2004년에 만든 3.0 이래로 그냥 brute-force 알고리즘을 그 부분만은 아직까지 최적화를 못 했다. 한글 입력 부분과 직접적인 관계가 없고, 딱히 크게 티가 나는 부분이 아니다 보니 지금까지 방치되어 온 것이다. <날개셋> 한글 입력기 6.0의 다음 버전은 이 부분을 개선하여, 이제 안심하고 Ctrl+Z를 꾹 누를 수 있는 프로그램이 될 것이다.

Undo 기능과 관련된 얘깃거리를 두 가지만 더 꺼내고 글을 맺겠다.

첫째, 예전에 한번 언급한 적이 있듯이, 프로그램들이 Undo는 거의 예외 없이 Ctrl+Z로 정착해 있는 반면 Redo는 단축키가 프로그램마다 일치하지 않는 경우가 있다. MS의 관행은 Ctrl+Y인 듯하지만 Ctrl+Shift+Z인 프로그램도 있다.
아래아한글은 도스 시절에 Ctrl+Y가 지우기 명령의 일종이기 때문에 주의해야 한다. Redo를 생각하고 눌렀다가는 Redo는커녕 텍스트를 지우면서 후폭풍으로 기존 Undo history까지 모두 날려 버리기 때문이다!

둘째, Multi-level undo를 잘 구현한 프로그램이라면, 문서의 modified 플래그 처리도 잘 되어야 한다. 무슨 말이냐 하면, 문서를 저장했다가 어딘가를 건드린 후(= modified 플래그 켜짐), Ctrl+Z를 눌러 그 작업을 철회한다면 문서는 당연히 다시 unmodified 상태로 바뀌어야 한다.
그리고 반대로, 저장한 문서에 대해서 Undo를 해서 modified 상태가 됐더라도, 그걸 다시 Redo로 철회했다면 문서는 unmodified로 되돌아가야 한다. 논리적으로 당연한 얘기이다. <날개셋> 편집기는 multi-level undo가 처음으로 지원되기 시작한 3.0 때 이거 하나는 아주 철저하게 잘 구현해 뒀다.

비주얼 C++ 에디터, 그리고 국산 에디터인 EditPlus는 이 플래그 처리가 잘 된다. MS 오피스 제품도 마찬가지.
그러나 AcroEdit는 이게 되지 않아서 불편하며, 아래아한글도 2007은 처리가 되지 않는다. WordPad 역시 지원 안 함.

Undo나 Redo 같은 Command history 기능은 문서의 modified 상태까지 예전으로 되돌리는 명령이기 때문에 문서를 건드리는(modified 플래그를 언제나 켜는) 동작보다 상위에서 돌아가야 할 텐데, 이 점을 미처 고려를 못 한 것 같다. Undo나 Redo나 문서를 고치는 기능인 건 매한가지이기 때문에 무조건 modified 상태로. ^^

Posted by 사무엘

2011/06/26 08:23 2011/06/26 08:23
, , ,
Response
No Trackback , 4 Comments
RSS :
http://moogi.new21.org/tc/rss/response/531

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++ 개발자에게 F12는 무척 특수한 의미를 갖는 단축키이다. 커서가 가리키고 있는 명칭(함수, 변수, 클래스 등~)이 선언되어 있는 위치로 바로 이동해 주는 기능이기 때문이다. Find in Files와 더불어 복잡한 소스 코드를 분석할 때 없어서는 안 되는 기능이다.

또한 Alt+F12는 Symbol 탐색기이다. 무수히 많은 파일들을 무식하게 문자 단위로 검색하는 게 아니라 최적화된 symbol 데이터베이스만을 뒤지기 때문에, 명칭만의 출처를 아주 빠르고 똑똑하게 찾을 수 있다.

사실 이 기능은 비주얼 C++ 6.0에도 있었고, 심지어 더 이전 버전도 갖추고 있었다. 그러나 그때는 이 기능이 활발하게 활용되지는 못했다.
이런 고급 기능을 사용하려면 프로그램의 전체 빌드를 Browse 정보를 남겨 놓는 방법으로 특수하게 다시 해야 했기 때문이다. 그리고 매번 빌드할 때마다 그 Browse 정보도 업데이트해야 했다. 그러므로 빌드 시간도 증가.

원래 C/C++이라는 언어 자체가 빌드 속도가 느린 데다, obj, pch, ncb 등 온갖 잡다한 output을 많이 남기는 걸로 악명 높은 언어이다. 언어의 범용성 보장이라든가 강력한 네이티브 코드 생성을 위해서 어쩔 수 없는 면모도 물론 있긴 하나, 현대의 언어들과 비교했을 때 생산성이 무척 떨어지는 건 사실. 그런데 그것도 모자라서 빌드 오버헤드까지 감수하면서 별도의 Browse 정보를 생성해야 한다니. Browse 기능을 쓰는 사람이 많을 수가 없었다.

내 말이 믿기지 않으면, 비주얼 C++ 6 갖고 계신 분은 프로젝트 하나 만들어서 아무 명칭에다 대고 F12를 눌러 보라. Browse 정보를 생성할 건지 묻는 질문부터 먼저 뜨는 걸 볼 수 있을 것이다.

그러다가 비주얼 C++ .NET이 출시되면서 장족의 발전이 이뤄졌다. 별도의 Browse 정보를 만들 필요가 없이, 빌드 한 번만 하고 나면 명칭 조회와 탐색이 아무 프로젝트에서나 가능해진 것이다. 굉장히 편리해졌다.

사실 이건 어찌 보면 자연스러운 귀결인 게, 비주얼 C++ 6.0부터는 어차피 인텔리센스 기능이 초보적인 수준이나마 추가됐기 때문이다. 함수의 원형이 마우스의 풍선 도움말로 뜨고 명칭을 자동 완성해 주는 기능은 Browse 기능과 성격이 상당수 비슷하지 않은가?

기술적으로 어떻게 변했는지 정확하게는 모르지만, 본인 생각에는, 둘이 서로 따로 DB를 구축하면서 따로 놀던 게 닷넷부터는 동일한 인텔리센스 데이터를 공유하면서 명칭 조회 기능과 인텔리센스가 모두 동작하도록 바뀌었지 싶다. 그래서 그런지, 편리해진 대신에 닷넷 초창기 버전은 과거의 6.0에는 있던 기능이 잠시 사라진 것도 있었다.

바로 함수에 대해서 Caller/Called by 그래프를 그려 주는 기능이다. 이 함수가 또 어떤 함수를 호출하는지 쭉쭉~ 아니면 이 함수를 사용하는 함수는 무엇이 있는지 쭉쭉~

그런데 인텔리센스 정도 구현하는 데는 명칭 자체에 대한 DB만 구축하면 되지, 명칭과 명칭 사이의 각종 인과관계를 따질 필요는 없지 않은가. 그래서 비주얼 C++ 2003(닷넷)에는 잘 살펴보면 저 기능을 어디에도 찾을 수 없다. 본인의 가설을 뒷받침하는 증거 중 하나이다.

잠시 없어졌던 그 기능은 비주얼 C++ 2005부터 완전히 부활했다. 인텔리센스 자체가 버전업을 거듭하면서 굉장히 강력해졌기 때문이다. 2003부터는 #define 심볼과 템플릿도 지원되기 시작했고, 2005/2008부터는 함수 포인터도 지원되기 시작했다. 예전에는 프로젝트를 별도로 빌드해서 파일로 조회를 해야 했던 정보가, 지금은 컴퓨터가 좋아진 덕분에 실시간 업데이트와 조회가 가능한 존재로 바뀌었다.

비주얼 C++ 2010은 듣자하니 인텔리센스 엔진이 또 완전히 바뀌었고, C#이나 베이직 같은 ‘쉬운 언어’에서나 지원되던... 빨간 선 기능(워드 프로세서의 맞춤법 검사기처럼.. 문법에 틀린 부분)이 흠좀무스럽게도 C++에도 도입되었다고 하더라.

인간의 프로그램 개발 환경의 생산성 개선을 위한 노력은 오늘날에도 계속되고 있다. ㄲㄲ

Posted by 사무엘

2011/06/07 19:10 2011/06/07 19:10
Response
No Trackback , 9 Comments
RSS :
http://moogi.new21.org/tc/rss/response/522

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

도움말의 역사

오늘날 PC의 GUI 환경에서 돌아가는 거의 모든 프로그램들은 F1을 누르면 도움말이 나온다.

윈도우는 운영체제 차원에서 표준 도움말 규격이 있는 것으로 예로부터 유명했다. 아예 운영체제의 API에 WinHelp 같은 함수가 정식으로 등재되어 있다. -_-
맥 OS는 모르겠고, 리눅스는 그런 시스템이 없다고 들었다(쉘부터가 GNOME이 뭔지 KDE가 뭔지 사실 아직도 알쏭달쏭... ㄲㄲ).

그 원조는 바로 WinHelp와 그 기반의 HLP 도움말 파일이다. 20년 전의 윈도우 3.0때 처음으로 도입된 이 기능은 나름 굉장히 유용했다. 다양한 서식을 적용한 텍스트 + 이미지 + 하이퍼링크 + 팝업창은 일종의 인터넷 WWW와도 비슷한 수준의 인터페이스였다. WinHelp는 의외로 기능이 다양해서 도움말에다 색인도 넣고, 도움말 창의 버튼도 customize 가능했다.

당시 WinHelp를 설계한 엔지니어가 누군지는 모르겠지만, 도움말이라는 간단한 주제 하나만으로 굉장한 대작을 만들어 냈다. 윈도우 3.1 때 도움말 시스템이 소폭 업그레이드되긴 했으나, 아직까지는 대동소이하고 하위 호환성 정도는 유지되었던 걸로 본인은 기억한다.

도움말은 기본적으로 오늘날 워드패드가 사용하는 RTF(서식 있는 텍스트) 기반이었다. 문서 파일에다가 각종 도움말 메타정보를 WinHelp 스펙대로 넣어 준 후, 이들 파일과 그림들을 Help Compiler로 컴파일하고 압축하면 HLP 파일이 생성되었다. 하지만 이건 대단히 번거롭고 까다로운 일이었기 때문에, 그 절차를 간소화해 주는 위지윅 도움말 저작 도구도 응당 개발되어 나오곤 했다.
16비트 윈도우용 SDK를 보면 도움말 컴파일러가 HC30 (윈 3.0 공용), HC31 (윈 3.1 전용)이 따로 있었다.

이 WinHelp는 윈도우 95에서는 4.0으로 버전이 올라가고 기능이 훨씬 더 강화되었다. 계층 구조의 목차가 따로 추가되어서(*.CNT) 도움말의 첫 화면에다 번거롭게 목차를 본문 형태로 넣을 필요가 없어졌으며, What's this?라는 풍선 도움말이 추가되었다. 창도 더욱 아담해지고 응용 프로그램과 통신만 잘 주고받으면 거의 CBT 수준의 인터렉티브한 도움말을 만들 수도 있게 됐다.

윈도우 3.x 시절에는 매 대화상자마다 한쪽 끝에 ‘도움말’ 버튼이 있는 게 유행이었는데 그게 95부터는 다 사라졌다. 그 대신 X 버튼 왼쪽에 [?] 버튼이 생겼다.

그리고 또 여기서 주목할 점은, 도움말 시스템이 16비트(winhelp.exe)와 32비트(winhlp32.exe)로 완전히 분리되었다는 것이다. 왜 그럴까?
윈도우 운영체제의 도움말은 단순히 하이퍼링크가 달린 RTF 문서 뷰어 수준을 훨씬 더 능가하는 방대한 시스템이었기 때문이다.

HLP 파일은 윈도우 API를 호출하는 건 물론이고 WinHelp 규격대로 만들어진 플러그 인 DLL들을 붙여서 도움말 화면을 사실상 마음대로 제어할 수 있었다. 나만의 버튼을 추가하고, 확장 기능을 넣고... DLL이 들어간 이상 16비트와 32비트의 분리는 불가피해진 것이다. 지금 같으면 32비트와 64비트의 분리가 필요하겠지.

얼마나 customize가 가능하냐 하면, HLP 파일에다가 마치 오늘날의 HTML 도움말(CHM)처럼 목차 탭을 도움말 내부에다 보조 윈도우로 집어넣을 수 있었다. 도움말이 WinHelp에다가 아예 없던 기능을 추가할 수 있을 정도였던 것이다.
과거 본인이 즐겨 이용하던 Paint Shop Pro 7은 Robo HelpOffice라는 저작 도구로 만들어진 HLP 도움말을 제공했는데, 정말 기능이 상상을 초월하게 화려했다.

이게 웹으로 치면 ActiveX이다. 도움말 세계의 ActiveX인 셈인 것이다. -_-;;

그랬는데, 윈도우 98 + 인터넷 익스플로러 4가 되면서 새로운 도움말 시스템이 또 등장했다. 서식 있는 텍스트+하이퍼텍스트의 진수는 바로 웹이 아니던가. RTF가 아니라 아예 IE의 엔진을 쓰는 도움말이 생긴 것이다. 이것이 오늘날까지 전해져 오는 HTML 도움말이며, 파일의 확장자는 CHM이다. Compiled HTML.

HTML 도움말은 내부적으로 IE를 쓰는 관계로 과거의 WinHelp보다 훨씬~ 더 덩치 크고 무거웠다.
IE 4를 얹지 않은 옛날 윈도우 95 시절의 탐색기 vs 오늘날 탐색기의 덩치 및 구동 시간은
과거 WinHelp 도움말 vs 오늘날 HTML 도움말의 덩치 및 구동 시간

이건 비슷한 구도이다. -_-;;;
하지만 웹에서 쓰이는 각종 자바스크립트+다이나믹 비주얼 효과를 도움말에서도 그대로 재활용 가능하다는 점을 감안하면, 웹 기술을 도움말에다 활용하겠다는 발상 자체는 훌륭하다고 볼 수 있다. WinHelp 기술은 윈도우 밖에서는 아무 쓸모도 없는 테크닉이지 않은가.

개발자의 입장에서야 RTF보다야 HTML이 훨씬 더 친근하니 예전보다 도움말 만들기가 쉬워진 것도 아주 좋다. 본인도 HLP 도움말은 만들 엄두를 못 냈었는데 CHM 도움말은 나모나 프런트페이지만으로도 비교적 손쉽게 만들 수 있었다.
홈페이지 만드는 데 쓰이는 파일을 그대로 모아서 컴파일만 하면 끝. 그러니 CHM 파일은 웹 문서 아카이브를 만드는 데도 아주 유용했다.

일반 웹에는 존재하지 않지만 도움말에는 필요한 기능이 있다. 가령, 팝업 메뉴를 띄운다거나 외부 프로그램을 실행하는 기능은 소스를 보면 MS가 자체적으로 ActiveX처럼 비표준 확장 태그를 써서 구현해 놓은 걸 볼 수 있다.

CHM 도움말은 장기적으로 기존 HLP 도움말 시스템을 대체할 목적으로 만들어졌기 때문에, HLP로 할 수 있는 일은 CHM으로도 다 할 수 있게 돼 있다. 가령, CHM으로도 풍선 도움말을 구현 자체는 할 수 있다. 하지만 그 쬐그만 풍선 도움말이 웹 페이지 내용이라는 건 영 안 어울린다. 실제로, 비스타부터 풍선 도움말은 윈도우 운영체제 내부에서는 완전히 사라졌다.

윈도우 98부터 XP까지 운영체제의 도움말은 WinHelp와 HTML 도움말이라는 양분된 구도를 유지하고 있었다. 그러다 윈도우 비스타는 과감하게 WinHelp를 없애 버렸다. HLP 도움말을 열면 ‘이 도움말은 옛날 버전으로 만들어져서 이제는 더 지원되지 않습니다’만 뜬다. (단, 16비트용 WinHelp는 남아있음)
원래 마소는 과거 호환성을 극도로 존중해 주는 집단이다. 그런데 왜 이런 조치를 취한 것일까?

오늘날 과거 호환성보다 더 중요한 건 보안이기 때문이다.

HLP와 CHM 모두 단순히 read-only 하이퍼텍스트 문서만 취급하는 게 아니다. 사용자의 컴퓨터에 있는 응용 프로그램을 실행할 수 있고, DLL의 코드를 불러와서 실행할 수 있다. 따라서 잠재적 보안 위험성도 충분하다.

마소는 21세기부터 자사 소프트웨어에 있는 이스터 에그를 모두 없앴으며, 이미 짜 놓은 수많은 코드에 대해서도 대대적인 보안 강화 리팩터링을 시작했다. 비주얼 C++ 2005부터는 잘 알다시피 비표준 오명을 감수하고라도 C 라이브러리까지 뜯어고쳐서 *_s 함수를 도입할 정도였다.

그랬는데 그렇잖아도 구닥다리 WinHelp의 코드를 보니까, 이건 기능도 카오스 그 자체이지, 앞으로 지원도 안 할 건데 리팩터링을 할 필요를 못 느낀 것이다. 그러니 철도 당국이 수익 안 나는 간이역을 폐역하듯이 지원 중단 결정을 내렸다. WinHelp 함수 지못미.

이런 보안 강화 정책으로 인해, 윈도우 비스타부터는 탐색기에 16비트 윈도우 실행 파일들이 아이콘이 그려져 나오지 않는다. 웹페이지의 파비콘을 추출하고 그리는 코드의 허점을 이용해서도 악성 코드를 주입하고 실행할 수 있을 정도이니 말 다 했다. -_-;; 비슷한 이유로, 워드패드에서 과거 wri 파일 포맷을 읽는 기능도 삭제되었다. 구닥다리 코드는 이제 와서 보안을 강화하는 작업을 하기 귀찮으니까 그냥 무시하기. ㄲㄲ

사실은, CHM 파일마저도 이제 MS가 더 적극적으로 개발을 안 하기는 마찬가지이다. 요즘 MS가 만드는 프로그램들은 CHM 안 쓰고 또 자기만의 다른 도움말 시스템을 쓴다. 비록 내용 렌더링이 HTML 기반인 건 동일하지만, CHM은 아니라는 뜻. 그 때문인지는 모르겠지만 HTML 도움말을 보면, 도구상자의 아이콘은 10년 전이나 지금이나 아직까지도 16컬러 그대로이다. ㄲㄲㄲ

아울러, CHM 역시 보안 위협을 많이 받는 관계로, 웹에서 받아서 바로 실행한 녀석은 내용이 표시되어 나오지 않는다. 반드시 로컬 환경에다 저장해서 ‘속성 -> 제한 해제’를 해 줘야 내용을 볼 수 있다.

앞으로 윈도우 운영체제의 도움말 시스템이 어떻게 변모할지는 알 수 없는 노릇이다. 하지만 설마 CHM이 HLP처럼 그렇게 갑작스럽게 호락호락 없어지지는 않을 듯하다.

하긴, 예전엔 아래아한글도 언어(한국어든 영어든)와 플랫폼(3.1/95/NT)을 불문하고 동일하게 표시되는 GUI 엔진을 표방하고서, 도움말조차 자체 포맷을 만들었던 적이 있다. 97까지만 해도 윈도우 3.1 도움말 스타일의 자체 도움말을 썼었는데 워디안/2002 이후부터는 싹 잊혀지고 그냥 CHM을 쓰기 시작했다.
도스용 프로그램 개발할 때 도움말 기능을 구현하던 추억이 아직도 새록새록하다. ^^

※ 잡설: 응용 프로그램의 보안 문제

유명한 국산 압축 프로그램인 빵집의 구버전에서, 악의적으로 일부 내용이 조작된 zip 파일을 열자 엉뚱하게도 내가 지정해 준 프로그램이 실행된다. 프로그램의 보안 취약점을 시연하는 동영상을 보니 신기하기 그지없었다.

프로그램의 소스로는 제각각의 이름으로 구분되는 수많은 변수와 함수의 명칭들이, 빌드 후에는 그저 아무 의미 없는 오프셋 내지 메모리 주소로 바뀐다. 그러니 이런 정교한 숫자가 조금이라도 바뀌면 프로그램은 전혀 다른 동작을 하게 된다. 그런 조작은 입력 파일의 조건 검사를 허술하게 하는 프로그램의 허점을 이용해서 가능하다. 더구나 zip은 프로그램 실행과는 전혀 관계없는 데이터 파일일 뿐인데, 하물며 대놓고 프로그램 실행 기능이 있는 파일은 얼마나 위험하겠는가?

사용자의 입장에서는 각종 보안 업데이트가 귀찮기 그지없다. 하지만 개발자의 입장에서는 보안 업데이트를 안 하면 어떻게 되는지를 너무 자세하게 설명해 줄 수도 없다. 그러니 서로 답답한 노릇이다.

“모방 범죄 예방을 위하여 더욱 정확한 후레쉬 조작법... 이 아니고 더욱 정확한 악성 코드 삽입 방법은 알려드리지 못하는 점 양해 바랍니다.” ㅋㅋㅋㅋ

Posted by 사무엘

2011/05/03 08:14 2011/05/03 08:14
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/505

※ 비주얼 스튜디오 2003

지금은 바야흐로 2011년. 비주얼 C++ 2010이 나온 지 이미 1년이 지났고 C++0x 규격까지 등장한 마당에, 그 옛날 버전인 비주얼 C++ 닷넷 2003 관련 블로그 포스트를 아직도 적지 않게 찾을 수 있어서 본인은 놀랐고 한편으로 동질감을 느꼈다.
본인도 <날개셋> 타자연습을 비롯해 여러 legacy 프로젝트들을 여전히 VS 2003으로 관리하고 있다.

특히 2005와 그 후대 버전들은 MFC 라이브러리가 너무 심하게 bloat되어서 본인은 업그레이드할 의욕을 대략 상실했다.
static link를 할 엄두를 못 내겠는데, dynamic link 정책도 영 괴상한 방식으로 바뀌니..
MFC 라이브러리보다도 덩치 더 큰 포토샵, MS 오피스급의 초대형 상업용 프로그램을 개발할 때라면 모를까, 이건 소규모 프로그램 개인 개발자에겐 영 아니라는 생각이 든다.

그래도 듣자하니 2010은 msvcr100과 mfc100을 굳이 winsxs 매니페스트 방식을 안 쓰더라도 자기 local 디렉터리에서 로딩 가능하게 바뀌었다고 하던데, 그건 그나마 다행인 점이다. 전세계에서 터져 나온 개발자들의 불만을 비주얼 C++ 팀이 받아들인 모양이다. Class wizard도 부활하는 등, 2010이 꽤 참신한 변화를 많이 했다. 2005->2008은 연도 차이가 3임에도 불구하고, 2일 뿐인 2008->2010보다 변화량이 훨씬 더 적었다.

잡설이 길었는데..
운영체제인 윈도우 비스타는 시스템 계층에서 바뀐 게 많다 보니, 예전의 2000/XP와는 달리 비주얼 스튜디오, 혹은 비주얼 C++에게 그리 자비롭지 않았다. 비스타뿐만이 아니라 7도 마찬가지.

구닥다리 6.0은 그런 최신 OS에서 동작 자체는 한다만, 설치하는 과정에서 무슨 문제가 있을 수 있다고 하고(OLEView 같은 일부 컴포넌트),
2003은 비스타에서 대놓고 좀 잡다한 문제를 일으킨다. 하지만 MS는 VS 2003 지원은 2006년 중반의 SP1을 끝으로 이제 완전히 끊었다. 비스타 이후부터는 버려진 자식. -_-;;

그 잡다한 문제 중 유명한 게 뭐냐 하면, Find in files 기능.
윈도우 비스타/7에서 VS 2003으로 이 명령을 내리고 있으면 IDE가 응답 없이 그대로 멎어 버렸다. 파일 검색 기능을 쓸 수 없다는 소리. 그런데 이건 개발자가 밥먹듯이 써야 하는 기능인데, 이거 없으면 불편해서 프로그램 개발 어떻게 하라고? -_-;;;

이 문제를 해결하는 방법은 의외로 간단하다.
탐색기로 DEVENV.EXE를 찾아가서 Alt+Enter로 속성을 꺼낸 후, 호환성 탭에서 시각 테마를 꺼 버리면 된다. 이 팁을 올린 각종 블로그 포스트에는 한국어와 영어를 불문하고 "너무 좋은 정보군요.", "알려 주셔서 대단히 고맙습니다", "퍼 갑니다" 댓글들이 즐비하다. 아직도 VS 2003 쓰는 개발자가 많다는 뜻 되겠다. X86 아키텍처와 PE 방식 실행 파일이 존재하는 한, C++, Win32 API, 네이티브 코드 자체가 근본적으로 유행을 그렇게 타는 분야가 아니니 말이다.

비주얼 C++ 2003은 MS 오피스 XP와 동일한 GUI 기반이며, 어차피 comctl32 6.0 기반의 시각 테마를 쓰지도 않는 프로그램이다. 그러니 프로그램 외형이 딱히 달라지지도 않는다.
단, 그 비주얼 C++로 실행한(디버거를 붙인 F5든, 붙이지 않은 Ctrl+F5든) 나의 프로그램도 시각 테마가 무시된 채 실행되므로 그건 주의해야겠다. 물론, 탐색기 같은 걸로 따로 실행하면 문제 없음.

덧붙이자면 VS 2003은 도킹 윈도우 같은 걸 드래그하여 이동할 때 점선으로 윤곽이 나타나는데, 이 역시 알다시피 Aero 하에서는 동작이 굉장히 굼뜬다.
이것이 VS 2005부터는 개선되어 파란 도킹 다이아몬드도 생기고 비주얼이 산뜻해졌으나, 어차피 2005조차도 비스타에서 제대로 돌아가지 않긴 마찬가지이다.

SP1에다가 비스타 패치까지 다 복잡하게 설치해야 한다. 문제는 SP1과 비스타 패치 각각이 VS 2005를 처음 설치하는 것만치 시간이 욕 나오도록 오래 걸린다는 것. ㅆㅂ
윈도우 비스타보다 늦게 나온 2008부터가 드디어 비스타에서 별 트러블 없이 잘 돌아가며, 내장하고 있는 플랫폼 SDK도 윈도우 비스타 기준 최신이다.

※ 32비트 프로그램이 64비트 프로그램 디렉터리에 접근하기

잘 알다시피 64비트 윈도우에서도 시스템 디렉터리의 경로는 32비트와 마찬가지로 windows\system32이다. 64가 아니다.
그럼 64비트 윈도우 내부에서 32비트 시스템 파일들이 들어가는 경로는 windows\SysWOW64이다.

그런데 본인은 며칠 전 굉장히 놀랐다.
GetSystemDirectory를 호출하는 코드를 32비트로 빌드하나, 64비트로 빌드하나, 실행 결과는 windows\system32로 동일했기 때문이다. 왜 그럴까?

이는 일종의 가상화 내지 redirection 메카니즘 때문이다.
64비트 윈도우에서 동작하는 32비트 프로그램은 애초에 64비트 윈도우 시스템 디렉터리로 접근을 아예 할 수 없다. system32와 syswow64가 모두 보이긴 하지만, system32 디렉터리를 들여다보면 운영체제가 보내 주는 것은 어차피 syswow64의 정보뿐이다. 그 안에서만 놀아야 한다.

Program Files 디렉터리는 그렇지 않아서 32비트 프로그램이 32비트용 경로와 64비트 경로로 모두 따로 접근이 가능하다. 하지만 어차피 known path를 운영체제 차원에서 얻는 방법이 없다. 64비트 프로그램은 64비트용 경로와 32비트용 경로에 모두 접근 가능하지만 32비트 프로그램은 64비트용 경로를 얻을 수 없다.

이렇게 가상화를 너무 잘 해 주기 때문에, 심지어 64비트 OS에서도 32비트 프로그램은 GetSystemInfo 함수를 호출하더라도 멀쩡한 64비트 x64 컴퓨터를 32비트 x86으로만 인식한다. 이 OS가 진짜 64비트인지 32비트 프로그램도 알려면, GetNativeSystemInfo라는 새로운 함수를 써야 한다.

32비트 윈도우에서 <날개셋> 한글 입력기 64비트 에디션은 당연히 설치가 되지 않지만, 64비트 윈도우에서 32비트 에디션은 설치가 가능하다. 이 경우, 편집기나 변환기 같은 프로그램이야 별 차이 없이 쓰겠지만, 외부 모듈이나 입력 패드는 당연히 64비트 프로그램에서 제대로 쓸 수 없다.

그래서, 64비트 윈도우에서 <날개셋> 32비트 에디션이 설치되었을 때, "에디션을 잘못 고르신 것 같은데, 가능하면 64비트 쓰시져?" 하는 경고 메시지를 띄워 주고 싶다. 그런데, 32비트 프로그램이 자기 주변이 64비트인지 파악하기가 의외로 쉽지 않아서 고민이다. 운영체제가 64비트인 경우, 자신이 64비트 모듈과 병행 설치도 되어 있는지 체크를 해야 하는데 파일 시스템이 워낙 저렇게 샌드박스화해 있으니 말이다. =_=;;

※ TlsGetValue와 에러 코드

파일을 읽어서 주어진 일을 처리하는 함수를 만들었다. 이 함수는 파일을 찾지 못하면 false를 즉시 리턴하며, 그 후 이 함수가 호출한 CreateFile 함수가 남긴 GetLastError 값을 바탕으로, 응용 프로그램은 에러 메시지를 찍는다는 게 본인의 계획이었다.

그런데 이 함수가 선언한 각종 객체의 소멸자 함수가 뭔가 처리를 하면서, 또 GetLastError 값을 바꿔 버리기 때문에 정작 파일 조작이 실패한 이유를 밖에서 알 수가 없게 되는 경우가 있었다.
도대체 어디서 에러 코드가 바뀌지? MSDN을 뒤져보다 본인은 깜짝 놀랄 수밖에 없었다.

일반적으로 윈도우 API 함수들은 동작이 실패했을 때만 에러 코드를 설정한다. 그러나 TLS 값을 되돌리는 TlsGetValue 함수는 성공일 때도 에러 코드를 에러 없음을 의미하는 0으로 설정함으로써, 예전 함수의 에러 코드를 덮어써 버린다. 왜냐하면 리턴값 0만으로는 진짜 TLS 슬롯 값이 0인지, 아니면 실패를 의미하는 0인지 알 수 없기 때문이다.

TlsGetValue 함수는 C/C++에 언어적으로 존재하지 않는 새로운 scope를 만드는 것이나 마찬가지인 함수이기 때문에 밥먹듯이 자주 호출된다. 성능이 매우 중요함에도 불구하고 이 함수는 예외적으로 언제나 에러 코드를 건드리도록 설계되어 있다.

이게 에러 코드인지, 정상적인 리턴값인지 알 수 없는 예로 GetExitCodeThread/Process 함수가 있다.
STILL_ACTIVE라는 값이 리턴되었는데, 이게 해당 스레드나 프로세스가 종료하면서 진짜로 리턴한 값인지, 아니면 그게 아직 종료되지 않은 상태인지.. 알 게 뭐야..;;
개인적으로 함수를 왜 저렇게 설계했는지 모르겠다. 어지간하면 성공/실패 여부를 별도의 인자에다가 따로 되돌리게 하는 게 훨씬 안전할 텐데.

Posted by 사무엘

2011/04/08 17:29 2011/04/08 17:29
, ,
Response
No Trackback , 7 Comments
RSS :
http://moogi.new21.org/tc/rss/response/493

1. 운영체제의 기반 언어

윈도우 운영체제의 기반 언어는 C이다. 유닉스만 C 기반이 아니다. ^^
물론 더 생산성이 뛰어난 MFC도 있고 닷넷 프레임워크도 있으며, 고급 기능 중엔 GDI+처럼 일부 C++ 기반으로 제공되는 API도 있다. 그러나 제일 아래를 들여다보면 역시나 C언어 냄새가 팍팍 나는 윈도우 API가 짱이다.

여기서 기반 언어라 함은, 운영체제가 자신의 기능을 어떤 언어의 바이너리 수준에 맞춰 직통으로 제공하냐와 관계가 있다.
문자열이 그 좋은 예 중 하나이다. C언어 기반인 운영체제에서는 0번 문자 문자열(null-terminated string)을 사용하는데, 파스칼이나 베이직처럼 0번 문자 문자열을 사용하지 않는 언어는 운영체제와 문자열을 주고받을 때 약간의 오버헤드를 감수해야 한다.

뭐, 0번 문자 문자열이라는 개념 자체가 C언어가 원조이지는 않은 것 같다만... 과거 도스의 API는 C 수준의 계층조차도 없어서 운영체제 API 호출은 닥치고 레지스터에 값 설정하고서 어셈블리 인터럽트를 날리는 식이었다. 함수 이름 같은 건 없고 인터럽트 번호만 존재했다.

한편, C보다 더 상위에 있는 C++은 함수 이름의 mangling(오버로딩 때문에 이게 반드시 필요함) 방식이 컴파일러마다 전혀 통일되어 있지 않아서 난리이며, 이는 C++ 클래스 라이브러리의 바이너리 배포를 어렵게 하는 요인이다. 닥치고 오로지 함수 이름만 알고 있으면 되는 C에 비해 C++은 함수 링킹이 얼마나 복잡한가? 함수 호출 한번 할 때 매개변수 개체에 대한 생성자, 소멸자, 복사 생성자 처리하는 것도 꽤 어려운 일이다.
그러나 만약 밑바닥부터 C++을 기반으로 만들어진 운영체제가 있다면, 그 방식도 응당 표준화가 되어 있을 것이다.

이런 부류의 지저분한 언어 계층의 바이너리 표준을 통합해서 소프트웨어의 컴포넌트화를 좀 수월하게 하려고 MS가 만든 녀석이 바로 COM이며, 게임계에서 유명한 DirectX가 대표적인 COM 기반 API이다.

컴퓨터 시스템이 발달하면서 이렇게 운영체제의 기반 언어도 당연하지만 점차 상위 단계의 언어로 올가라가는 경향이 있다.
닷넷 프레임워크의 기반 언어는 잘 알다시피 C#이다. 아예 자바 기반 운영체제도 있다고 들었다. 그래서 요즘 3대 메이저 스마트폰은(윈도우 모바일, 안드로이드, 아이폰) 앱 만드는 언어가 서로 다 다르다.

덧붙이자면, 어느 운영체제의 기반 언어가 되기에 충분할 정도로 C스러운 이념을 지닌 언어들과는 달리, 파이썬(Python)은 뭔가 독자적인 위상이 있는 인터프리터 지향 언어이고 루아(Lua)는 host 언어와의 glue를 지향하여 특히 게임 개발처럼 코드와 데이터의 경계가 모호한 분야에서 자기 살 길을 찾은 언어인 것 같다. 운영체제의 바이너리 기반 언어라기보다는 매크로 언어가 되기 좋은 언어라고나 할까?

2. Objective C

아이폰 덕분에 덩달아 각광받고 있는 맥 OS의 기반 언어는 Objective C이다(이하 옵C). 정확히 말하면 코코아 API의 기반 언어라고 한다. 클래식 매킨토시 시절부터 옵C만 써 왔다는 소리인지? 그리고 하필 그런 유별난 마이너 언어를 선택한 이유가 있는지 궁금하다.

똑같이 객체 지향 언어라지만 옵C는 C++과는 구조가 생각한 것보다 굉장히 달라서 본인은 적지 않게 놀랐다. C++이 C의 큰 틀을 그대로 계승하고서 C 문법에서 이건 좀 아니다 싶은 부분만 고친 후(함수를 반드시 선언한 후 쓰게 고친 것 등) OOP 개념을 추가했다면...
옵C는 C의 strict superset인지라 C스러운 부분은 그대로 C답게 놔둔 후, Smalltalk에서 영향을 받은 OOP 문법을 그대로 추가했다.

- 옵C에서 추가된 예약어들은 앞에 @가 붙는다. 이건 C/C++에서는 전혀 쓰이지 않는 문자이다.
- 맥 OS X의 전신 NextStep에서 유래된 NS* 명칭 (MFC로 치면 Afx* 뻘 되겠다.)
- #import는 C/C++의 #include와는 달리 중복 include 방지가 자동으로 적용된다.
- C++에서는 true/false가 예약어로까지 도입되었지만, 옵C에서는 YES/NO를 쓴다.
- 클래스 메소드(C++의 static 멤버 함수)와 인스턴스 메소드(C++의 일반 멤버 함수)를 각각 +와 -로 구분하여 표기
- null pointer를 의미하는 nil이 존재한다. C++은 0x에 가서야 nullptr이 추가되었지 싶다.
- this 대신 self. void *대신 id
- 일부 C++ 컴파일러가 비표준으로 제공하는 __super 키워드가 옵C에는 있음
- 자동으로 실행되는 생성자· 소멸자 함수 같은 건 없으며, new/delete 문법도 다름

저런 건 오히려 사소한 차이일 뿐이고, 진짜 적응이 안 되는 건.. object에 대한 멤버 함수 호출이 [ ]를 동원하여 C++과는 완전히 다른 문법과 의미라는 점이다. 처음엔 “왜 이런 걸 만들었을까? 아이폰 앱은 이런 괴랄한 언어로 개발되고 있었던 거야?” 같은 생각마저 들 정도였다. 옵C는 그래도 C++보다는 훨씬 더 작고 단순하고 파싱하기 쉬운 언어이며, 컴파일 타임 위주인 C++보다는 런타임에 언어 차원에서 보장해 주는 요소가 더 많다.

C++의 클래스 멤버 함수 호출은 this 포인터만 암시적으로 추가된 일반 C 함수와 거의 다를 바 없다. 그러나 옵C는 OOP의 구현에 관한 한, C와의 호환성 내지 성능보다는 원칙에 더욱 충실한 듯하다. 멤버 함수는 메시징이라는 개념으로 구현하며, 잘은 모르지만 보내어진 메시지가 어떤 종류인지 런타임 때 파악이 가능할 정도로 그 체계가 유연하다고 한다.

C++로 클래스 라이브러리 DLL을 만들면 함수 프로토타입 하나만 바뀌어도 바이너리 호환성이 다 깨지는데(특히 그게 가상 함수였다면.. ‘더 이상의 자세한 설명은 생략’ ㄲㄲ) 그에 비하면 천국인 셈. 물론 성능 오버헤드는 있다.

또한 옵C에도 자바의 generic 같은 게 있어서 어떤 자료형이든 담을 수 있는 컨테이너 정도는 구현 가능하다고 들었다. int면 int, string이면 string만 담을 수 있고, 어떤 자료형이든 담는 컨테이너를 만들려면 Variant라는 개체 자체부터 만들어야 하는 C++ 템플릿과는 물론 살짝 다른 개념이다.

옵C는 그럼 라이브러리나 컴포넌트는 어떻게 만들고 컴파일/링크, DLL 같은 건 어떤 형태로 구현되는지 모르겠다. 어쨌든 언어 스펙을 보고 본인이 내린 결론은, C++ 코드를 옵C로 포팅하기란 쉽지 않겠다는 것. 포토샵처럼 맥 세계에서 먼저 유명했던 프로그램도 처음엔 C/C++로 개발되었다고 들었는데 맥도 C/C++로 가벼운 네이티브 코드 GUI 프로그램을 만드는 방법이 없을 리가 없을 것이다.
아, 그런데 문자열보다도 더욱 중요한 함수 호출 구현한 방법이 양 언어가 워낙 너무 다르다 보니 운영체제와의 소통은 어떻게 하려나 모르겠다. (C 스타일의 callback 함수가 제일 간단하고 짱 -_-)

옵C와 XCode에 흥미가 가긴 하지만, <날개셋> 한글 입력기가 맥에 상륙하기란 내 힘으로는 역시 무리일 것 같다.
또한, 본인은 garbage collector가 없는 건 괜찮아도, 자동으로 실행되는 생성자와 소멸자, 연산자 오버로딩, 템플릿, namespace를 갖추지 않은 언어로는 불편해서 코딩을 못 할 것 같다. ㄲㄲㄲㄲㄲㄲㄲㄲ

참고로 Objective C++라는 언어도 있다고 한다. 흠좀무..

Posted by 사무엘

2011/03/25 09:23 2011/03/25 09:23
, , ,
Response
No Trackback , 7 Comments
RSS :
http://moogi.new21.org/tc/rss/response/485

윈도우 프로그래머라면 이미 다 아시겠지만, 비스타에서부터 task dialog라는 아주 참신한 UI 기능이 추가되었다.
구닥다리 MessageBox를 쓰자니 뭐가 많이 부족하고,
그렇다고 해서 겨우 에러 메시지 하나 찍자고 별도의 대화상자를 또 만들자니 너무 번거로운데
task dialog는 가히 사막에 있는 오아시스 같은 존재가 아닐 수 없다.

사용자 삽입 이미지
위의 그림은 바로 task dialog의 뼈대. (출처: MSDN)

이제 당장 운영체제부터가 상당수의 UI를 task dialog으로 구현하고 있고,
메모장부터 워드패드까지 모든 기본 프로그램들의 “문서를 저장하시겠습니까?” 대화상자도 죄다 task dialog로 바뀌었다.
덕분에 Yes / No 일색이던 버튼이 Save / Don't save로 바뀐 걸 알 수 있다. task dialog는 각 버튼들에 들어가는 텍스트를 사용자가 자유롭게 지정 가능하기 때문이다.

Y/N이라고만 하면 이게 무슨 질문에 대한 “예/아니요”인지, 응답에 대한 결과를 사용자가 한 단계 더 추론을 해야 한다.
그러나 대놓고 “저장함/저장 안 함”이라고 표시를 해 주면, 이 선택으로 인해 야기되는 결과를 사용자가 더 직관적으로 알 수 있다. MS는 저런 UI 용어 하나하나까지 세심하게 검토를 해 온 것이다.

이것뿐만이 아니라 또 개인적으로 본인은 task dialog가 유용하다고 가장 먼저 느낀 면모가 뭐냐 하면,

“다음부터 이 확인 질문 안 하기” 부류의 체크 상자를 간단하게 추가할 수 있다는 점이었다. 과거의 MessageBox에서 진짜로 2% 부족한 면모였다.
그래픽 모드나 해상도를 바꾼 뒤에 타이머를 걸어서 “화면이 잘 나타나 보입니까? n초 이내에 응답이 없으면 원래 모드로 되돌립니다”를 구현하는 것도 이 task dialog로는 드디어 가능하다. 예전에는 그런 걸 구현하려면 전용 대화상자를 따로 만들어야 했다.

task dialog에는 인터넷 URL 링크를 넣을 수 있고, 라디오 버튼을 넣어서 사용자의 간단한 선택을 받을 수도 있다. 제목-본문 형태로 텍스트를 깔끔하게 배치할 수 있다는 것도 아주 좋은 점이다.
물론, 워낙 기능이 많기 때문에 사용하기가 다소 까다롭다는 건 어쩔 수 없다. 그래서 이를 간소화하기 위해, 비주얼 C++ 2008의 확장팩 내지 2010부터는 MFC에도 CTaskDialog라는 클래스가 추가되었다. 자료구조 관리는 이 클래스가 다 알아서 해 주기 때문에 사용자는 코드 한 줄로 간단하게 원하는 버튼, 원하는 컴포넌트들을 대화상자에다 추가할 수 있다.

그런데 task dialog로 할 수 있는 일은 단순히 메시지를 찍고 사용자로부터 간단한 피드백을 받는 일에 국한되지 않는다.
progress bar를 넣는 기능이 있고 bar의 상태를 일정 주기로 업데이트까지 가능하기 때문에, 이를 이용하면 진행 상황 표시 대화상자도 간단하게 구현 가능하다.

본인은 task dialog를 제어하는 코드와 스레드 작업 관련 코드를 한데 합쳐서 별도의 클래스를 만들어 이를 개인적으로 매우 즐겨 사용한다. task dialog를 사용하는 형태는 딱 정해져 있으니까 별로 customize를 하지 않고, 작업 상황 표시와 작업 스레드의 customization이 이 클래스의 존재 목표가 되는 셈이다.

task dialog 콜백과 스레드 콜백 함수는 내부의 private static 함수로 숨겨 놓는다. 스레드 콜백 함수는 this 포인터에 대해서 아래의 순수 가상 함수를 호출한다.

virtual UINT Work() = 0; //오버라이드 할 것
volatile int m_nCurPos, m_nPosMax; //현재/전체 진행 상황
volatile bool m_bCancel;

그리고 task dialog 콜백은 당연히.. 주기적으로 m_nCurPos 값을 체크하여 progress bar를 업데이트한다.
사용자가 도중에 취소 버튼을 눌러 버렸다면, m_bCancel 플래그가 설정된다. 작업 스레드는 이 값을 수시로 체크해서 사용자가 중단을 요청했다면 신속히 작업을 중단해야 할 것이다.

일이 언제 끝날지 모르는 작업에 대해서는 게이지가 marquee 형태로 뱅글뱅글 돌기만 하게 만들 수도 있다. 윈도우 부팅할 때처럼 말이다.

다만 한 가지 아쉬운 것은, task dialog는 진행 상황 표시만 전문으로 하는 녀석이 아니다 보니, progress bar를 두 개 표시해 주는 기능은 없다는 점이다.
설치 프로그램이라든가 압축/FTP 유틸리티처럼 파일을 다루는 프로그램들은 현재 처리하고 있는 파일의 진행률과 그리고 전체 작업의 진행률을 한데 표시하고 있으며, 이건 매우 흔한 관행이다. 이건 여전히 내가 직접 대화상자를 만들어야 할 것 같다.

.
.

그나저나 드디어 윈도우 7도 SP1이 정식 출시된 지 한 달쯤 됐다.
콘솔에서 세벌식으로 한글 입력할 때 한글+기호 입력이 제대로 안 되던 버그도 고쳐졌으려나? (난 7 안 써서 잘 모르겠다) 했는데
어느 지인의 얘기에 따르면 여전하다고 하네... -_- 어쩌라고.

Posted by 사무엘

2011/03/17 08:32 2011/03/17 08:32
, , ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/481

« Previous : 1 : ... 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : ... 31 : Next »

블로그 이미지

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

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/04   »
  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:
2674824
Today:
1516
Yesterday:
1540