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

1.
겨울방학도 이렇게 끝이 보인다.
본인이 이번 방학 때 이뤄낸 가장 뜻 깊은 성과를 둘 꼽자면 하나는 <날개셋> 한글 입력기 6.5이고, 다른 하나는 HFT(아래아한글 전용 글꼴) 해킹 성공이다.

사용자 삽입 이미지

저 글꼴들을 MS 오피스 제품에서도 쓰고 PDF도 자유롭게 만들고, 무엇보다도 화면에 anti-alias가 된 부드러운 모습으로 보니 너무 좋다.. 근성의 reverse engineering 오덕질을 통해서 이뤄 낸 성과. ㅋㅋ 새로운 글꼴로 아무 글이나 마구마구 써 보고 싶다.

또한, 날개셋 6.5 버전은 아직까지도 프로그램을 크게 고친 부분이 없을 정도로 역대 최고로 손꼽히는 안정성과 완성도로 잘 만들어졌다. 대단히 만족스럽다. 그래서 당분간 안심하고 완전히 새로운 기능 연구와 논문 준비 등에 전념할 수 있을 것 같다.

2.
윈도우 7은 콘솔(명령창)에서 세벌식을 쓰면 '다다.' 이렇게 한글이 덧나는 버그가 있다. 왜 SP1에서도 안 고쳐진 걸까? 예전에도 언급한 적이 있지만, 이런 건 두고두고 디스를 좀 해 줘야 된다.
윈도우 운영체제는 NT 계열도 꼭 이런 이상한 버그가 역사적으로 하나씩 있었다.

과거 2000은 256색으로 들어갔다가 돌아오면 군청색 제목 표시줄의 색깔이 옅어지는 버그를 유일하게 갖고 있어서 SP4에서까지 안 고쳐졌고,
XP는 테마를 저장했다가 불러오면 Luna 모드에서도 메뉴가 클래식 모드처럼 표시되어 색깔이 이상해지는 버그가 있는데 역시 SP3에서까지 안 고쳐지고 저렇게 끝났다.

이런 이유로 인해 본인은 한글 IME 개발과 관련하여 까탈스럽고 안 좋은 추억 때문에 남들이 7 좋아하는 것만치 7을 좋아하지는 않으며, 남들이 비스타 싫어하는 것만치 비스타를 싫어하지도 않는다. -_-;; 뭐, 비스타도 희한한 버그 의심 증상이 하나 있긴 했으나, SP1에서 곧바로 고쳐짐.

3.
<날개셋> 편집기는 txt 확장자를 자기 프로그램으로 연결한다거나 하지는 않는다.
그렇기 때문에 이렇게만 놔 둬서는 윈도우 7의 jump list를 활용하지 못한다. (윈7 사용자 중에 jump list가 뭔지 모르는 분은 없으리라 생각되지만, 어쨌든 모른다면 검색 요망)

탐색기에서 txt 파일을 우클릭하여 '연결 프로그램 선택 → 찾아보기' 등을 골라서 <날개셋> 편집기를 한 번이라도 지정한 뒤(꼭, 기본 연결을 시켜 놓을 필요는 없고 이렇게만이라도), 나중에 <날개셋> 편집기의 열기 대화상자로 txt 파일을 열고 나면 그건 앞으로 jump list 에 등재되게 된다.

jump list를 좀 더 창의적으로 활용하면, 편집기는 당장 저런 기본 용도만으로도 충분할 것이고(최근 파일 열기),
변환기는 클립보드 변환 같은 자주 사용할 만한 task를 등록해 놓을 수 있겠으며,
입력 패드는 자주 쓰는 보조 입력 도구를 실행과 동시에 바로 꺼내 놓게 할 수 있겠는데 더 자세한 활용법에 대해서는 좀 더 시간을 두고 고민해 봐야겠다.

4.
얼마 전엔 드디어 <날개셋> 한글 입력기 프로젝트를 비주얼 C++ 2010용으로 정식으로 포팅해서 빌드해 봤다. 특이사항으로는,

- 사소한 컴파일 에러가 있었으나, 더 깔끔하고 분명한 코드를 만드는 데 도움이 되는 에러였으며 쉽게 잡았다.
- VS 2010의 빌드 시스템은 $(TargetPath) 변수의 값을 예전과는 다른 방식으로 부여하는 듯하다. 그래서 이걸 조정하는 노가다를 매 프로젝트들마다 좀 해야 했다.

이것 외엔 딱히 트러블이 없었으니 무리 없이 잘 갈아탔다.

동일한 옵션으로 빌드했지만 x86 바이너리(32비트)들은 VS 2008과 비교했을 때 크기가 살짝 더 커졌고, x64 바이너리(64비트)들은 살짝 더 줄어들었다.
같은 코드를 빌드했을 때 바이너리 크기가 조금씩 더 커지는 건, VC6 이래로 개발툴이 업데이트되면서 비교적 일관되게 관찰되는 추세였다. 최적화가 인라이닝 등 코드 크기를 더 키우는 쪽으로 행해져서 그런 것 같다.

비주얼 C++ 2010은 C/C++ 언어도 빌드 중에 'Linking...'이라는 말이 안 뜨고 generating code...에 링킹이 포함되는 듯하다.
똑똑한 인텔리센스는 부러운 점이긴 하다만, 너무 커진 덩치, 이질감이 생긴 GUI와 도움말 시스템 때문에 2010은 개인적으로 언제쯤 도입하게 될지 모르겠다. 다만, 리소스 에디터가 드디어 윈도우 비스타의 PNG 내장 아이콘(256*256)까지 제대로 표시해 주는 점은 마음에 든다.

5.
내 경험상 윈7은 USB 메모리(스틱 or 외장 하드) 매체의 제거를 예전 OS에 비해 더 관대하게, 더 빨리 허용해 주는 것 같다. 해당 드라이브를 사용하는 프로그램들을 다 껐는데도 '사용 중이기 때문에 제거 못 함' 꼬장 때문에 할 수 없이 아예 OS를 로그오프하거나 아니면 그냥 강제로 매체를 제거해 버린 일이 거의 발생하지 않았다.

그리고 다른 얘기이다만, 윈도우 7은 Taskbar에 있는 각종 프로그램들 아이콘과 시스템 트레이의 아이콘을 드래그하여 마음대로 순서를 바꿀 수 있는 게 무척 인상적이다.
7에서 새로 바뀐 작업 표시줄은, 실행 중인 프로그램과(동일 프로그램이 중복 실행된 것 포함) 그렇지 않은 프로그램의 구분이 잘 되아 보이는 걸 개인적으론 안 좋게 생각했었다. 그러나 한동안 써 보니까 이게 그럭저럭 나쁘지 않은 디자인이라는 생각이 든다.

무엇보다도, 창을 몇 개씩 띄워 놔도 많이 띄웠다는 느낌이 심리적으로 안 드는 게 인상적임.
옛날에 윈9x의 전통적인 시작 메뉴 시절엔, 컴을 몇 년 쓰면서 수십 종류의 프로그램들을 설치하고 나니까 '프로그램' 메뉴 옆으로 프로그램 리스트가 두 칼럼 이상씩 차지하는 크고 아름다운 면적으로 주렁주렁 달렸던 거 기억하는가?

또한 인터넷 서핑하다가 브라우저 창이 열몇 개씩 넘어가니까 작업 표시줄 모습이 가히 가관으로 바뀌던 것도 기억하시는지? 윈도우 7은 복잡도를 제어하는 디자인에 무척 신경을 썼다..

6. 윈도우 비스타와 7 모두, 로그인 화면에서 암호를 입력하고 나면, 암호가 맞든 틀리든 일단 Welcome부터 출력하면서 설레발을 치다가 그 뒤에 암호가 틀렸으면 사용자 진입을 거부한다. “안 돼! / 돼!”도 아니고 츤데레도 아니고 이건 도대체 무슨 디자인일까?? -_-;;
암호가 맞을 때만 Welcome을 출력하게 개선되면 좋겠다.

7.
윈도우 9x는 프로그램을 조심해서 짜는 데에 도움을 준다.
NT 계열에서는 해제했던 메모리를 중복 해제하거나, 자원을 반납· 해제하는 걸 깜빡하는 식으로 대충 대충 짜도 당장 티가 안 나며 그냥 넘어간다. 그러나 9x에서 그랬다간 얼마 못 가 시스템 자원이 바닥난다거나 바로 뻗어 버리기 때문에, 이런 차이 덕분에 프로그램을 윈도우 9x에서 테스트하다가 버그를 발견하여 구조적인 문제를 해결한 경우가 지금까지 종종 있다.

아마 <날개셋> 한글 입력기도 한 2~3년 동안 윈9x에서 테스트를 안 한 채 개발을 계속하다가 버전이 1.0쯤 올라간 뒤에 다시 윈9x용으로 테스트하면, 여기저기서 원인을 알 수 없는 버그가 자꾸 튀어나와서 단순히 유니코드 API layer를 쓰는 것만으로는 윈9x를 결코 다시 지원할 수 없는 수준에 이를 것이다.
지금 <날개셋> 한글 입력기 소스가, 비록 같은 C++언어이지만 비주얼 C++ 6.0으로는 도저히 개발을 계속할 수 없는 이질적인 단계에 도달한 것처럼 말이다(각종 문법 차이 때문).

Posted by 사무엘

2012/02/23 08:33 2012/02/23 08:33
, , , ,
Response
No Trackback , 8 Comments
RSS :
http://moogi.new21.org/tc/rss/response/645

윈도우 운영체제에는 잘 알다시피 DLL이라는 게 있어서 한 프로세스를 구성하는 코드들을 여러 모듈로 분할할 수 있고, 반대로 동일한 코드를 여러 프로세스가 동시에 효율적으로 공유할 수 있다. 유닉스 계열의 운영체제에는 이와 비슷한 개념으로 shared library (*.so)라는 게 있다.

윈도우 DLL은 주소 공간이 해당 DLL을 로딩한 프로세스(EXE)에 완전히 종속된다. 그렇기 때문에 DLL이 사용하는 코드는 공유될지언정, 그 DLL이 선언하는 전역변수 같은 건 EXE마다 제각각이며, 심지어 동일 EXE를 여러 번 실행하더라도 제각각이다. 이것은 유닉스의 shared library와 다른 점이다. 윈도우에서 진짜 여러 프로세스들이 공유할 수 있는 메모리를 만들려면 내부적으로 공유되는 메모리 섹션을 별도로 생성해 놔야 한다.

이런 차이로 인해 특별히 조심해야 할 점이 있다. 한 EXE 안에서 3개의 DLL이 돌아가고 있고, 이들은 모두 동일한 버전의 비주얼 C++로 개발되어 동일한 CRT 라이브러리를 사용한다고 치자. 만약 이들이 모두 CRT를 DLL로 링크하여 동일한 CRT 라이브러리의 코드와 데이터를 공유한다면, 어느 모듈에서 malloc/new한 메모리를 다른 모듈에서 곧바로 free/delete해도 된다.

그러나 이들이 제각각 CRT를 static link했다면 그럴 수 없다. 한 모듈에서 할당한 메모리는 반드시 동일한 모듈에서만 해제해야 한다. 비록 메모리를 할당하고 해제하는 코드는 실질적으로 동일하지만 해당 코드가 동작하는 context는 모듈들이 모두 서로 다르기 때문이다. 모듈간에 메모리 할당과 해제를 자유롭게 하려면 각 모듈들은 자신만의 메모리 할당/해제 함수를 외부에다 별도로 제공해 줘야 한다.

DLL을 만드는 일은 64비트 운영체제가 등장하면서 다소 까다로워졌다. 32비트와 64비트 사이에는 DLL의 교차 로딩이 되지 않기 때문이다. 즉, 32비트 모듈(EXE/DLL)은 64비트 DLL을 읽을 수 없으며, 반대로 64비트 모듈은 32비트 DLL을 읽을 수 없다. 다시 말해, x64 운영체제에서도 x86 EXE를 아무 차이 없이 실행은 할 수 있지만, 그래도 64비트 EXE가 32비트 DLL을 내부적으로 읽을 수는 없으므로 착오 없기 바란다.

한 주소 공간은 전부 32비트 아니면 전부 64비트뿐이지, 두 종류의 코드가 섞여 있을 수가 없어졌다. 옛날과는 달리 지저분한 썽킹 계층 같은 게 없다. 동일 코드를 32비트와 64비트용으로 제각기 빌드해서 다같이 내놓아야 한다.
그러니 태생적으로 반드시 네이티브 코드 DLL을 만들어야 하는 컴포넌트/미들웨어/드라이버 분야라든가, 훅킹 내지 운영체제의 shell extension을 만드는 쪽은 다른 어떤 분야보다도 진작부터 64비트 프로그래밍이 필요했다. 사실은 IME 쪽도 예외가 아니다.

그런데 문제가 있다. 지금까지 DLL은 코드를 담는 용도로만 쓰여 온 게 아니라는 점이다. 잘 알다시피 윈도우 운영체제는 실행 파일의 포맷 차원에서 리소스라 하여 나름 계층을 갖춘 custom 데이터를 간편하게 불러오는 기능이 있다. 일일이 메모리 할당을 할 필요가 없이, 운영체제가 알아서 메모리 주소를 잡아서 로딩해 주고, API 함수 호출 한 번에 데이터를 곧장 찾아 주기까지 하니, 상당히 편리하다. 그래서 데이터 리소스만 갖춘 DLL도 엄청 많이 쓰였다.

특히 다국어 지원을 위한 외국어 리소스를 집어넣는 데 DLL보다 더 좋은 수단은 지금까지 별로 없었다. 운영체제의 대화상자 내지 string table 같은 주요 리소스 파일의 포맷은 32비트나 64비트나 바뀐 게 없다. 호환성 차원에서 일부러 동일하게 유지시킨 듯하다. 비주얼 스튜디오 200x의 MSDN(Document Explorer)이 사용하는 *.hxs 파일도 리소스 전용 DLL이다.

그런데 DLL은 태생적으로 컴퓨터 기계 종류에 지극히 종속적인 코드를 담는 게 주 목적인 파일 포맷이다. 그렇다면 기계 종류에 관계없이 동일한 데이터를 담는 DLL도 기계별로 일일이 다 따로 만들어야 할까?
그렇지는 않다. 데이터밖에 들어있지 않은 리소스 전용 DLL을 위해서 운영체제는 다음과 같은 배려를 하고 있다.

먼저, DLL을 읽을 때 흔히 사용하는 LoadLibrary 대신, LoadLibraryEx 함수는 LOAD_LIBRARY_AS_IMAGE_RESOURCE 같은 플래그를 제공하여 DLL의 코드 부분을 전혀 감안하지 않고 데이터 부분만 읽게 할 수 있다. 이렇게 하면 해당 DLL은 DllMain 함수 자체가 실행되지 않으며, 자신과 호환되지 않는 기계를 타겟으로 만들어진 DLL도 읽을 수 있다. 물론, FindResource 같은 함수로 리소스 추출만 가능할 뿐, GetProcAddress 같은 기능을 사용할 수는 없다.

다음으로, DLL 자신이 리소스 전용 DLL일 뿐이라고 명시해 줄 수 있다. 비주얼 C++의 DLL 프로젝트에서 링커 옵션을 보면 /NOENTRY가 있다. 이 옵션이 지정되면 그 DLL에는 아무 코드도 삽입되지 않으며, 진입점인 DllMain 함수 자체가 없는 리소스 전용 DLL임이 인증된다. 이런 DLL은 외부에서 그냥 대놓고 LoadLibrary로만 호출해도 기계 종류에 관계 없이 읽을 수 있다.

윈도우는 공유 라이브러리를 다루는 개념이 유닉스 계열과 차이가 있을 뿐만 아니라 실행 파일을 로딩하는 방식에도 개념적인 차이가 있다. 윈도우는 position-dependent, 즉, 주소 종속적인 방식이다. 윈도우의 EXE와 DLL에는 preferred address라는 게 있어서, 이 메모리 주소에 딱 로딩이 되면 아주 성능이 좋지만, 그 주소에 로딩이 못 되면 재배치 페널티가 따르는 방식을 사용한다. 재배치 작업을 어떻게 하면 되는지에 대한 재배치 정보가 reloc이라는 섹션에 있다.

EXE야 Win32s 같은 과거의 열악한 환경이 아닌 이상, 자신만의 고유한 주소 공간이 있기 때문에 언제나 preferred address에 로딩된다는 보장이 있다. 그에 반해 남의 주소 공간에 달라붙는 형태인 DLL은 그렇지 못하기 때문에 일반적으로 반드시 reloc 섹션이 필요하다.
다만, 이런 재배치 작업도 코드가 없는 리소스 전용 DLL에는 전혀 해당사항이 없다. 리소스 내부에 DLL의 메모리 주소에 종속적인 숫자 데이터 같은 게 있을 리가 없기 때문이다.

그러니 이론적으로 리소스 전용 DLL은 reloc 정보를 생략해 버려도 괜찮지만, 그냥 대놓고 생까-_- 버리는 것도 곤란하다. 윈도우 2000 미만의 옛날 운영체제의 경우 DLL을 preferred base에다 로딩을 못 하는데 재배치 정보마저 없다면, 원래 재배치를 할 게 없는 리소스 전용 DLL임에도 불구하고 그냥 일방적으로 로딩을 거부해 버리게 된다.

재배치를 안 해도 괜찮은 DLL이라는 별도의 플래그는 윈도우 2000 이상에서부터 도입되었다. 물론, 애당초 기계어 코드가 들어있지 않은 DLL의 reloc 섹션에 의미 있는 재배치 정보 자체가 있을 리가 없다. 그냥 껍데기뿐인 잉여인 것이다.

이렇듯, DLL은 원래 코드를 공유하려고 만들어졌지만 기계와는 무관한 리소스나 데이터를 공유하는 container 역할도 결코 무시할 수 없는 위치에 있다. 심지어 트루타입(TTF) 글꼴이 도입되기 전에 윈도우에서 쓰이던 비트맵/벡터 글꼴인 FON 파일은 16비트 형태의 리소스 전용 DLL로, 오늘날의 64비트 윈도우에서도 그 잔재가 남아 있다!

그래서 운영체제가 리소스 전용 DLL에 대해서는 예외적으로 기계를 가리지 않고 읽을 수 있고, 또 그런 DLL에는 불필요한 정보를 합법적으로 생략도 할 수 있게 별도의 배려를 해 왔음을 우리는 윈도우 API의 변천사를 통해 알 수 있다.
그러고 보니, 32/64비트 응용 프로그램이 각각 32/64비트에 해당하는 윈도우 시스템 디렉터리나 각종 프로그램 디렉터리를 얻어 오고 접근하는 법도 꽤 복잡해져 있는데, 이건 다음 기회에 다루도록 하겠다.

Posted by 사무엘

2012/02/19 08:29 2012/02/19 08:29
,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/643

살다 보니 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

비주얼 C++ 관련 잡설

1. 비주얼 C++ 한글판

마이크로소프트에서 한글화한 프로그램의 UI에서 이런 저런 오역이 발견되는 건 어제 오늘 일이 아니다. 뭐, “안녕하신가, 힘세고 강한 아침!” 수준의 막장 발번역-_-은 아니지만, 이런 오역이 간간히 발견되는 주된 이유는, 번역자가 해당 소프트웨어가 다루는 분야의 용어를 잘 알지 못해서일 것이다. 그리고 어떤 문장이나 단어가 실제로 프로그램의 어느 부분에서 등장하는지를 모르는 채, 그냥 번역 리스트만 쭉 보면서 아무 문맥 정보가 없이 기계적으로 번역만 했기 때문일 것이다.

마이크로소프트가 개발한 소프트웨어 개발툴 중 비주얼 베이직은 5던가 6 시절부터 이미 한글화가 되었다. 그 반면, 가장 어렵고 하드코어한 개발툴인 비주얼 C++ 6은 한글화되지 않았으며 닷넷에서부터 통합 IDE가 제공되는 과정에서 드디어 한글화가 됐다. 그러나 베테랑 개발자 중에 한글판 IDE를 선호하는 사람은 거의 없으며, 이 점에서는 본인도 마찬가지이다.

옛날에 유니코드라는 것도 없고 PC의 환경이 극도로 열악하던 시절에는 한글판이 대놓고 영문판보다 성능이 열등했다. 텍스트 모드에서 한글 바이오스를 띄웠을 때와 띄우지 않았을 때의 성능 차이는 말할 나위도 없고, 도스 시절에 한글 QuickBasic은 성능은 둘째치고라도 그야말로 퀵라이브러리(qlb) 파일 포맷이 영문판과 호환조차 되지 않던 쓰레기-_-였다.

영문 윈도우 95는 4MB 램에서 그럭저럭 돌리는 게 가능했던 반면, 각종 무거운 한글· 한자 글꼴을 얹어야 했던 한글 윈도우 95는 최하 6~8MB 램이 필요했다. 그것도 어지간한 PC의 메모리가 4~8MB 사이이던 시절에!
난 아직도 기억이 생생한 게, 펜티엄급 노트북에서 IE4를 띄웠는데 빽빽한 영문으로 된 사이트는 비교적 매끄럽게 스크롤된 반면, 빽빽한 한글이 적힌 사이트(그냥 굴림체 비트맵 글꼴 크기)는 스크롤이 상당히 굼떴었다.

그도 그럴 것이 윈도우 세계에서는 '한글'이 그것만 특별 취급해 줘야 하는 문자가 아니었으니, 당시의 도스용 프로그램들처럼 효율적인 조합형 한글 입출력 메커니즘이 쓰이지 않았다. 게다가 한국에서 완성형이 주류 표준이다 보니 다국적 소프트웨어라면 한글을 2350자 내지 11172자의 그림문자처럼 취급할 수밖에 없었기 때문이다.

물론 세월이 흐르고 흘러 지금은 언어에 따른 성능 격차는 없기에 앞서서 측정 자체가 무의미해진 건 사실이다. 지금은 성능 격차 때문에 일부러 영문 원판 소프트웨어를 찾아 쓸 필요는 없다. 그러나 비주얼 C++ 같은 프로그램은 어차피 아무나 쓰는 프로그램도 아니고, 핵심 용어들에 대한 어설픈 번역에 이질감과 거부감이 들어서 한글판을 안 쓴다고 보는 게 타당하겠다.

단적인 예를 들어 보겠다. 아래 스크린샷을 보라.

사용자 삽입 이미지

먼저, output 창에 있는 컴파일 에러 로그를 보자. Illegal case를 '대/소문자가 잘못되었습니다'라고 오역한 건, 비주얼 C++이 처음으로 한글화된 200x 이래로 지금의 무려 2010에서까지 고쳐지지 않았다. 번역자가 C++ 프로그래밍에 전혀 무지하거나, 이 문장이 어느 문맥에서 쓰이는지를 하나도 알지 못한 채 번역했음이 분명하다. 세상에 C++이 컴파일러 차원에서 코드의 대소문자 오류를 분간해 주는 언어였던가. ㄲㄲ

비주얼 스튜디오 2010은 C#에 이어 C++까지도 코드의 오류가 있는 부분에 빨간 점선을 그어 준다. 물론 C++ 코드는 C# 코드보다 분석하기 훨씬 더 힘들기 때문에, 이는 내부적으로 완전한 형태의 컴파일러를 백그라운드로 돌림으로써 상당한 양의 CPU 오버헤드와 디스크 용량을 대가로 치른 끝에 구현된 편의 기능이다.

마우스를 case문 에러가 있는 곳으로 가져가 보면, 에러 메시지가 뜻밖에도 컴파일러가 뱉은 것과는 표현이 다르다. 그런데 '스위치'라고? 이건 case를 대소문자라고 옮긴 것보다는 덜 심각한 오역이지만, 이 역시 번역자가 문장을 제대로 이해를 못 하고 번역한 것 같다. 혹시 기능을 켜고 끄는 물리적인 스위치를 생각한 건 아닐까? 스위치를 음역하지 말고 그냥 'switch문'이라고 옮기는 것이 더 정확할 것이다.

2. 비주얼 스튜디오 2010의 GUI customization

비주얼 스튜디오와 MS 오피스 제품(지금처럼 리본 UI가 도입되기 전)은 그야말로 자신만의 화려하고 강력한 GUI를 갖추고 있었다. 메뉴와 도구모음줄은 운영체제가 자체 제공하는 녀석이 아닌 독자 구현 버전을 썼으며, 정말 과잉 투자 잉여라는 생각이 들 정도로 모든 GUI 구성 요소를 사용자 입맛에 맞게 바꿀 수 있었다. 도구모음줄의 배치는 두말 할 나위도 없고, 등록해 놓을 명령, 그리고 심지어 아이콘 그림과 기능 명칭까지도!

내 기억이 맞다면 이거 원조는 MS 오피스 97이다. BCG나 Xtreme toolkit처럼 이런 GUI 엔진만 짝퉁으로 구현하여 미들웨어 형태로 파는 업체도 응당 있을 정도였다.

이런 GUI 엔진이 탑재된 프로그램은 메뉴에 Tool(도구) - Customize(사용자 지정)라는 명령이 있었고, 이 대화상자는 약간 특이하게 동작을 했다.
보통 modal 대화상자가 떠 있는 동안은, 상위의 응용 프로그램 윈도우는 그 대화상자를 닫을 때까지 전혀 반응을 하지 않게 된다.
그런데 그 Customize 대화상자는 비록 modal 형태이지만, 그게 떠 있는 상태에서 마우스로 도구모음줄을 클릭하거나 메뉴를 누르면 도구모음줄이 반응을 했다. 도구모음줄 아이콘을 드래그하여 배치를 바꾸거나 없애거나, 콤보 상자의 경우 폭을 조절할 수 있고 우클릭하여 아이콘이나 설명문을 고칠 수 있었다.

즉, 평소에 도구모음줄을 우클릭하면, 나타내거나 감출 도구모음줄을 선택하는 메뉴만 뜨지만, Customize 중에 도구모음줄을 우클릭하면 해당 도구모음줄 아이콘을 고치는 더 세부적인 명령이 떴던 것이다.
메뉴에서 자주 쓰는 기능을 도구모음줄에다가도 좀 올려 놓으려면, 메뉴를 연 뒤에 해당 기능을 원하는 도구모음줄에다가 Ctrl+드래그만 하면 끝이었다.

사용자 삽입 이미지

그런데... 그런데... 비주얼 스튜디오 2010은 GUI 엔진이 싹 바뀌면서 저런 예외적이고 특이한 기능을 다시 구현하기가 대략 곤란했는지..
Customize 대화상자와 도구모음줄이 자연스럽게 연동하는 기능이 완전히 없어졌다.
대화상자가 떠 있는 동안은 도구모음줄을 전혀 건드릴 수 없다.

도구모음줄을 고치는 걸 전적으로 대화상자 안에서만 해야 한다.
내가 원하는 명령을 도구모음줄에다가 좀 추가하려고 했는데, 내가 원하는 도구모음줄과 내가 원하는 명령을 일일이 복잡한 리스트에서 찾으면서 정말 불편하고 번거롭기 그지없었다.
그리고 콤보 상자(빠른 찾기, 솔루션 플랫폼, 빌드 configuration 바꾸는 것 등)의 폭을 좀 바꾸려고 했는데 세상에나...
폭을 픽셀 단위 숫자로 입력해야 한다. -_-

사용자 삽입 이미지

예전에는 마우스 드래그로 간편하게 됐던 것이 상당히 퇴보한 게 아닐 수 없다..;;
난 개인적으로 GUI 운영체제에서, 화면으로 결과를 당장 볼 수 있는 값을 숫자 하나 달랑 입력받게 해 놓은 UI를 싫어한다. 가령, 객체를 회전하는 것만 해도 MS 오피스는 회전축을 잡고 마우스로 드래그함으로써 결과를 실시간으로 보면서 쉽게 할 수 있는데, 아래아한글 2007은 각도를 숫자로 입력해야 하고, 만족스러운 각도가 나올 때까지 사용자가 시행 착오를 겪어야 한다.;;

그런데 그런 불편한 방식을 비주얼 스튜디오 2010이 답습한 셈이다.
Customize 기능을 없앨 수는 없으니까, 그냥 이런 형태로 대충 대체 UI를 집어넣은 거라는 인상을 지울 수 없다.;;

딱 하나 좋아진 게 있다면,
예전의 customize 방식은 편리한 대신, 편법 UI인 만큼 오로지 마우스로만 접근 가능하고 키보드로는 하는 게 아예 불가능했는데 이제는 대화상자를 다루는 것이니 키보드로도 얼마든지 가능해졌다는 것.
사실, 가장 이상적인 건 둘을 모두 갖추는 것이긴 한데 이건 비주얼 스튜디오 2010에서 아쉬운 면모가 아닐 수 없다.

아울러 덧붙이자면, VS 2010도 Alt+F11을 눌러서 매크로 편집기를 열어 보면 그건 하나도 안 바뀌었고 예전의 VS 2008 IDE가 거의 그대로 뜬다.

Posted by 사무엘

2011/11/21 08:32 2011/11/21 08:32
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/602

전산학 전공자 내지 IT 분야 종사자에게는 상식으로 통용되는 당연한 개념이다만..
오늘날 범용(generic-purpose) 컴퓨터에서 돌아가는 소프트웨어는 크게 세 가지 형태로 나뉜다.

1. 로컬

흔히들 PC로 대표되는 컴퓨터에서 stand-alone으로 동작하는 전통적인 프로그램이다. Windows야 그렇다 치더라도 오피스, 비주얼 스튜디오 같은 업무용 프로그램은 아직 로컬 프로그램의 아성을 무너뜨릴 영역이 없다.
가장 역사가 길고, 가장 빠르고 효율적으로 동작하며, 특정 컴퓨터 아키텍처(기계어)와 운영체제의 실행 파일 포맷에 종속적이다. 그래서 이쪽 개발 환경은 전통적으로 C/C++ 같은 저수준 최적화 언어가 강세이다.

물론 클라이언트가 아닌 서버 프로그램은 성격이 약간 다르긴 하나, 서버 프로그램 자체는 역시 서버라는 로컬 컴퓨터 자신의 자원만을 이용하여 동작한다. 여객 운송과 화물 수송의 차이와 비슷한 맥락이다. 그리고 사실은, 다음에 설명할 2.웹 프로그램을 돌려 주는 기반도, 클라이언트든 서버든 1.로컬 프로그램들이 다 마련해 주고 있다. 그러니 로컬 프로그램은 앞으로도 없어질 수는 없다. 단지 전체 소프트웨어에서 차지하는 비중이 줄어들 뿐이다.

옛날에는 불특정 개인 사용자를 대상으로 하는 상업용 제품은 패키지 형태로 발매되곤 했지만, 오늘날은 인터넷의 발달과 극심한 불법 복제로 인해 이런 전통적인 형태의 배포의 비중이 굉장히 줄어들었다. 오늘날 국산 패키지 소프트웨어는 아래아한글과 V3 말고 있나? -_-;; 또한 보안 위협으로 인해 이런 프로그램 역시 한번 설치하고 끝이 아니라 끊임없는 보안 패치와 업데이트의 필요성이 커져 있기도 하다.

2. 웹

개인용 컴퓨터의 성능이 굉장히 향상되고 그에 따라 웹 표준이 발달하면서 웹브라우저, 정확히 말해 WWW는 단순히 그림과 하이퍼링크가 동원된 문서라기보다는 거의 프로그래밍 플랫폼처럼 오래 전부터 바뀌었다.

웹 프로그래밍의 최대 매력은 로컬을 월등히 능가하는 범용성과 기계 독립성, 생산성이다. 브라우저에서 사이트 접속만 하면 바로 실행..;; 마치 게임처럼, 클라이언트와 서버, 코딩과 디자인 등을 두루 아우르는 종합 예술처럼 보이기도 한다. 가령, 옛날에는 GWBASIC이나 LOGO로 어린 학생들에게 그래픽 프로그래밍 교육을 시켰다면, 지금은 그냥 HTML5만 써도 될 것이다.

물론, 로컬 개발에 비해서는 혼자 독립적인 작품을 만든다는 느낌이 좀 덜 들며-_-, 기술이 아직까지 안정화해있지 않은 면모가 있고, 로컬 컴퓨터 자체를 세밀하게 제어할 수 없으며 성능이 떨어진다는 한계도 있다. 가령, 오피스 제품군이 웹 애플리케이션으로 완전히 대체될 날은 과연 글쎄?
그러나 앞으로 웹 프로그래밍의 비중은 절대 무시 못 할 것이고 수요도 없어지지 않을 것이다.

3. 앱

스마트폰에서 동작하는 '로컬' 프로그램이라고 볼 수 있지만, 그 성격이 역시 1과는 사뭇 다르다.
스마트폰 자체는 PC보다 성능이 떨어지기 때문에, 로컬에서 모든 처리를 마친다기보다는 서버에다 input을 보내서 받은 output을 보여주는 형태의 앱이 많다. 또한 스마트폰은 화면이 작고 PC 같은 빠른 문자 입력을 할 수 없기 때문에, PC와는 다른 독자적인 GUI가 필요하다. 터치스크린은 마우스와 완전히 동일한 포인팅 UI가 아니다. (대표적으로 hovering이란 게 없다) 다만, PC에는 없는 기울임, 흔들림, 방향, 현재 위치 같은 특수한 입력을 받아들일 수 있다.

스마트폰은 PC만치 사용자가 컴퓨터 내부를 완전히 손쉽게 제어할 수 있는 물건은 아니다. 그래서 PC용 프로그램보다는 더 엄격한 과금 체계를 갖추고 프로그램을 배포하여 수익을 낼 수 있다.
스마트폰 앱은 역사가 짧기 때문에 PC 같은 지저분한 호환성 잔재 같은 게 덜하고, 일찍부터 자바든 C#이든 객체지향 언어와 가상 기계 바이트코드 기반의 프로그래밍 환경이 잘 구축돼 있다. 깔끔한 최신 프로그래밍 인프라가 기본으로 제공된다는 뜻이다.

오늘날 스마트폰 CPU는 ARM 아키텍처밖에 없지만, 그래도 커널 말고 다른 응용 프로그램들은 네이티브 코드가 아니다. 그런 .NET이나 자바 같은 가상 기계 자체가, 1~3(로컬, 웹, 앱) 사이의 이질감을 낮추고자 만들어진 것이기도 하고 말이다.
아울러, CPU의 성능이 좋아졌을 뿐만 아니라 LCD 디스플레이 소자가 보편화하고 통신 기술이 발달하면서 스마트폰 같은 물건도 대중화될 수 있었다.

20세기 중반까지만 해도 컴퓨터는 곧 메인프레임-단말기 모델이었다.
컴퓨터라는 게 무진장 비싼 물건이고 자원이 귀하다 보니, 모든 처리는 중앙 컴퓨터에다 맡기고 각 사용자는 단말기로 서버에 접속해서 명령 프롬프트에서 서버의 기능을 사용하곤 했다. 그때는 컴퓨터는 대학, 연구소, 정부 기관, 군대의 전유물이었고, 개인용 컴퓨터라는 개념을 감히 떠올리기조차 쉽지 않았었다. (알파넷이 미국이 아닌 소련에서 발명되었다고 생각해 보자. 그게 오늘날의 인터넷으로 발전할 수 있었을까? -_-)

그러다가 20세기 말에는 PC가 대세가 되었다. 개인용 컴퓨터 하나만으로 어지간한 일은 다 할 수 있게 되었다. 비유하자면, 만원버스에 시달리면서 출퇴근하다가 번듯한 자가용이 생긴 셈.
PC의 사고방식으로는 소위 PC 통신은 어쩌다 한 번씩만 다른 컴퓨터에 접속하는 특별한 작업이며, 웹브라우저 역시 오피스 패키지처럼 별도로 구입해서 사용하는 특수한 프로그램일 뿐이다.

그 후 오늘날 대세라고 회자되고 있는 건 일명 클라우드 컴퓨팅이다. 개인용 컴퓨터가 무진장 작아지고 통신 인프라가 발달한 덕분에, 예전처럼 부족한 자원을 공유하려고 컴퓨터들을 연결하는 게 아니라 진짜 유비쿼터스 세상이 돼서 컴퓨터들을 연결한다. PC 통신 시절에만 해도 하이텔 단말기가 있었는데 오늘날의 스마트폰에 비하면 얼마나 격세지감인가!

전세계 컴퓨터가 다 인터넷에 연결되고 클라이언트와 서버의 구분이 무의미해지고, 궁극적으로는 (거의) 모든 작업이 웹 프로그램만으로 해결되고 모든 자료가 웹에 저장되는 세상이 온다. 예전에는 PC끼리 자료 전송을 위해서 플로피 디스켓이나 USB 메모리를 썼는데, 이제는 사용자의 로컬 컴퓨터나 스마트폰 그 자체가 플로피 디스켓이나 USB 메모리와 마찬가지가 된다는 뜻.

이걸 역시 자동차에다 비유하자면 이렇다. 사람이 직접 자가운전을 하니까 교통사고가 발생하고 도로가 막히고 여러 문제가 생기다 보니, 전세계 도로가 한데 통제되고 지능형 임대 자가용이나 궤도 교통수단이 생겨서 모든 사람들이 그걸 간단히 이용하는 형태가 된 셈이다.
물론 이게 온전히 실현되려면 시스템적으로나, 보안 쪽으로나 해결해야 할 문제가 많다.

Posted by 사무엘

2011/10/14 08:26 2011/10/14 08:26
, ,
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/584

비주얼 C++ 2010 써 보다

* 옛날에 썼던 이 글과 연계되는 내용이다.

비주얼 스튜디오 2010을 드디어 회사에 깔아 봤다. 극심한 뒷-_-북.
인터넷 익스플로러 9만 보고도 “세상에 MS가 이런 UI의 프로그램도 만들다니, 오래 살고 볼 일이다”란 생각을 한 적이 있는데, VS 2010도 과연 그러하다.
개인적으로 시커먼 남색 배색이 별로 마음에 들지는 않다만..;;. 어째 이런 비주얼을 만들 생각을 했을까 싶다.

듣던 대로 IDE의 GUI 껍데기는 밑바닥부터 완전히 바뀌어서 다시 작성되었다.
닷넷 200x 시절은 비록 비주얼은 살짝 다를지언정 그래도 MS 오피스 엔진의 흔적이 남아 있었고 닷넷 초창기 버전인 2002/2003은 아예 오피스 XP의 GUI를 그대로 차용했었는데, 이제 비주얼 스튜디오의 GUI는 오피스와는 전혀 관계 없는 독자적인 엔진 기반이다.
그러고 보니 비주얼 C++ 6은 MFC를 사용하여 오피스와는 관계 없는 독자적인 GUI였는데... ^^;;

윈도우 운영체제의 모든 GUI는 메뉴에서 상하 화살표를 누르고 있으면, 비록 사용 불능(disabled)이라 할지라도 모든 항목이 순서대로 순회된다. 난 이게 MS 사의 전통인가 싶었다. 운영체제의 표준 메뉴부터 시작해 MS 오피스 등 MS에서 만든 역대 제품들을 모두 살펴보기 바란다.
그러나 VS 2010의 메뉴는 불능 항목는 아예 선택되지 않고 skip된다. 이 점에서는 과거 도스용 아래아한글의 동작과 비슷해졌다.

하다못해 이런 사소한 메뉴 GUI의 동작에서부터도 본인은 MS에서 만든 프로그램 같지 않은 이질감이 곧바로 느껴졌다.
덧붙이자면 VS 2010의 메뉴는 언제나 화면이 확 펼쳐지지 Fade나 Slide 같은 애니메이션 효과가 나타나지도 않는 것 같다.

IDE의 로딩 시간과 덩치는 확실하게 크고 아름다워졌다.
단, 인텔리센스는 확실히 예전 버전보다 더 똑똑해진 게 느껴져서 편하다. *.ncb 파일 대신 다른 방식의 인텔리센스 DB를 쓰는데, 역시 프로젝트 하나당 수십 MB씩 용량을 무지막지하게 차지하는 건 변함없다.
닷넷 시절 거의 10년 가까이 사용해 온 Document Explorer 기반 도움말(MSDN) 시스템도 갈아엎었다고 하는데 자세한 내역은 잘 모르겠다. 단, 매크로 IDE는 과거의 비주얼 스튜디오 2008 IDE를 그대로 쓰고 있음.

프로그래머용 에디터에 화면 확대/축소 기능이 생겨서, 단순히 글씨 크기만 바꿀 때는 옵션 대화상자를 꺼낼 필요가 없게 된 건.. 상당히 참신하다. 그래도 조절을 할 수 있으니까 유용하다.
<날개셋> 편집기도 글씨 크기 조절 기능 건의가 지금까지 한두 번 들어온 게 아니니 말이다. =_= (하지만 프로그램의 구조와 개발 방향의 특성상, 실현 가능성은 제로)

뭐, IDE와 GUI 얘기는 여기까지 하고...
비주얼 스튜디오는 2005 이후에 3이 더해진 2008 버전보다도, 2가 더해진 2005나(2003에서 버전업) 2010이(2008에서 버전업) 변화 사항이 많았다.
다만, 2003과 2010은 그 해 4월에 출시되었고 2005는 그 해 말(10~11월), 그리고 2008은 아예 2007년 말에서 2008년 초에 가깝기 때문에 실제 출시 간격은 2년 반에서 큰 차이가 없다고 볼 수도 있겠다.

역사적으로 MS 제품들이 2000년대 중반에 운영체제는 XP와 비스타 사이, 오피스는 2003과 2007 사이, IE는 6과 7 사이에 간격이 굉장히 길었다. 이에 반해 비주얼 스튜디오는 그런 제품들과는 무관하게 버전업이 꾸준히 되어 온 셈이다.

과거 MSVCR71.DLL, MFC71.DLL에 이어, MSVCR100.DLL과 MFC100.DLL도 이젠 그냥 편하게 윈도우 시스템 디렉터리에 들어가 있다. 정말 감개무량하다. VS 2005와 2008이 사용하는 CRT/MFC DLL만(80, 90) 잠깐 winsxs 밑으로 숨었었는데, 그 방식이 배포하기가 너무 불편해서 다시 일반 DLL 로딩 방식으로 되돌아간 것이다.

VC 6의 유물이던 클래스 마법사가 다시 생긴 것도 신선한 충격. 굳이 MFC 기반 프로젝트가 아니어도 유용해 보인다.
하긴, 6 시절까지만 해도 클래스 마법사가 효율적으로 소스를 파싱하라고 메시지 맵에 //AFX_MSG 같은 이상한 주석 부호도 있었는데.. 그게 필요 없어진 게 닷넷부터이다.

VC 2010은 모처럼 C++ 언어 문법도 제법 확장되었으니 이것도 짚고 넘어가지 않을 수 없겠다.

auto와 nullptr은 가뭄에 단비 같은 유용한 키워드이다.
전자는 본인이 예전에도 논평했듯이, 번거로운 타이핑과 typedef를 획기적으로 줄여 준다.
그리고 후자는 숫자로 쓰이는 0과 포인터로 쓰이는 0을 확실하게 구분하여 C++ 함수의 오버로딩 때 모호성을 해소해 준다. explicit과 비슷한 맥락에서 추가되었다고도 볼 수도 있겠다.

다만, 기존 코드와의 명칭 충돌을 최대한 피하기 위해 null이나 NULL, 심지어 nil도 아닌 nullptr로 예약어가 정해졌다는 건 감안할 필요가 있음.
또한, 기왕 auto가 추가됐을 정도면 상위 클래스를 자동으로 가리키는 super 같은 키워드도 C++에 같이 좀 추가하지 하는 아쉬움이 있다. 비주얼 C++은 MS 확장 차원에서 __super가 있긴 한데 말이다.

문득 드는 생각인데, 순수 가상 함수를 선언할 때 쓰이는 0은 숫자에 가까울까, 포인터에 가까울까?
숫자의 성격이 강하다면 0 대신 false를 써도 되겠고, 포인터의 성격이 강하다면 0 대신 nullptr을 쓰면 되겠다. 하긴, true와 false는 진작부터 C++ 예약어로 추가됐는데 말이다. 이제 C++에는 0을 의미하는 키워드가 둘 존재하게 됐다.

뭐, 요약하자면, 덩치가 딥다 커졌는데, 커진 만큼 덩치값 하는 편의 기능도 많고 기능면에서 바뀌고 향상된 것도 많다. 다만, 비주얼은 내 눈에는 여전히 좀 이질적임. ㅋㅋ
간단하게 VC 2010으로 <날개셋> 한글 입력기 프로젝트를 빌드도 해 봤다. 개발용으로는 2010으로 언제쯤 완전히 갈아탈지는 미지수이다.

<날개셋> 한글 입력기는 1.x부터 2.4까지는 VC 6.0을 썼고, 2.5부터 5.3x까지는 6년 동안 VC 2003을 썼다. 그러다가 5.5부터는 지금까지 약 2년간 VC 2008을 쓰는 중. 2005는 64비트 에디션을 빌드할 때만 잠깐 쓰다가 이마저도 2008로 곧 대체됐다. ^^;;

난 개인적으로 비주얼 C++에 대해 실현 가능성이 별로 없는 두 가지 희망 사항이 있다.

첫째, MFC나 플랫폼 SDK 같은 공통 프로그래밍 요소들의 인텔리센스 정보들은, 매번 번거롭게 각 프로젝트별로 중첩해서 들어가는 게 아니라 이미 만들어져 있는 걸 공유할 수 있으면 좋겠다. 이것만 해도 인텔리센스 파일 크기가 엄청나게 줄어들 것이다. -_-;;

그리고 둘째, 운영체제의 legacy known DLL인 msvcrt.dll과 mfc42.dll에다가 바로 링크하는 기능도 좀 있으면 좋겠다. 런타임 dll을 배포하지 않고, static link 하지 않고도 작은 바이너리 배포를 할 수 있게 말이다.

덩치가 커지는 것 자체가 문제가 아니라, '불필요하게' 덩치가 그것도 꽤 부담될 정도로 커지는 게 문제이다. I hate bloatwares. -_-

Posted by 사무엘

2011/08/13 08:11 2011/08/13 08:11
,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/554

윈도우 운영체제가 제공하는 파일 목록 탐색 API로는 FindFirstFile, FindNextFile가 있다.
사실, 도스 시절에도 C언어에는 내부적으로 도스 API를 사용하는 _findfirst, _findnext 같은 함수가 있었는데, 윈도우 API 역시 그 인터페이스를 거의 그대로 차용했다.

파일을 탐색하는 동작은 state가 존재하는 costly한 작업이기 때문에, 파일을 여닫는 것처럼 핸들을 주고받는 과정이 수반되며, 탐색이 끝나고 나면 그 핸들을 반드시 닫아 줘야 한다.
state가 존재하는 덕분에, 파일 탐색을 하는 도중에 다른 디렉터리에 대해 다른 파일 탐색 작업을 시작할 수도 있다. 이게 가능해야 재귀적으로 하위 디렉터리 다단계 탐색을 할 수 있을 것이다. 참고로 C 표준 함수 중 strtok 함수는, state가 존재함에도 불구하고 state 핸들값을 별도로 받지 않아서 디자인상 문제가 있는 함수라고 까였음..

본인은 운영체제가 제공하는 파일 탐색 함수의 인터페이스에 대해 다음과 같은 불만이 있다.
먼저, 파일 탐색 동작을 식별하는 핸들값 HANDLE과, 파일이 계속 존재하는지를 판단하는 BOOL값을 따로 관리해야 한다는 것이다. FindFirstFile은 HANDLE을 되돌리고, FindNextFile은 BOOL을 되돌린다. 그래서 이들을 가지고 for문이라도 만들려면 두 변수를 모두 갖고 있어야 한다. (말만으로는 실감이 잘 안 갈 테니, 관심 있으신 분은 파일 탐색 루틴을 직접 짜 보기 바란다.)

MFC의 CFileFind는 기존 API 함수를 거의 그대로 캡슐화했지만 다행히 FindFirstFile에 해당하는 FindFile 함수도 동일하게 FindNextFile과 마찬가지로 BOOL을 되돌려서 그나마 낫다.
또한 소멸자는 자동으로 FindClose를 호출해 주며, 지금 찾은 파일에 대한 정보를 별도의 GetFilePath 같은 멤버 함수를 통해 얻어 올 수 있다. 그래서 아래와 같은 형태로 loop을 작성하면 된다.

CFileFind fnd; BOOL b;
for(b=fnd.FindFile(L"*.txt"); b; b=fnd.FindNextFile())
  Use(fnd.GetFilePath());

본인은 한술 더 떠서 이렇게 독자적으로 만든 클래스를 즐겨 사용한다. 생성자와 소멸자를 빼면 다들 연산자 오버로딩이다.

class CMyFileFind {
public:
  CMyFileFind(PCTSTR pszFile);
  ~CMyFileFind();
  const WIN32_FIND_DATA *operator ->() const;
  operator bool() const;
  void operator++(int);
};

for(CMyFileFind fnd(L"*.txt"); fnd; fnd++)
  Use(fnd->cFileName);

짠~
파일 탐색을 생성자에서 바로 시작할 수 있고, WIN32_FIND_DATA에 파일 정보가 존재하는지의 여부를 bool 형변환 연산자가 바로 알려준다. 그리고 ++ 연산자가 다음 파일 탐색을 의미하며, -> 연산자를 통해 찾은 파일 정보를 곧바로 얻을 수 있다. 깔끔하지 않은가? ㄲㄲ

개인적으로, FindNextFile 함수는 더 발견된 파일이 없는 경우 주어진 찾기 핸들을 자동으로 close해 버리는 기능도 있으면 좋겠다.
파일 탐색 기능에 앞으로 되돌아가는 기능이 있는 것도 아닌데(=PrevFile 같은 거라도..;;), 더 찾을 파일이 없으면 이 핸들은 닫아 버리는 것 말고 도대체 다른 용도가 있는가? 놔 둘 이유가 전혀 없다.
이렇게 되면 파일을 찾다가 중간에 멈추는 게 아닌 이상, FindClose를 번거롭게 또 호출해야 할 필요가 없어져서 좋을 것이다.

이 찾기 핸들의 자료형은 HANDLE이다. 하지만 파일이나 스레드 같은 커널 오브젝트가 아니어서 그런지, CloseHandle이 아니라 반드시 FindClose 함수로 닫아야 한다. 그리고 실패를 의미하는 값이 NULL이 아니라, 마치 CreateFile의 실패값처럼 INVALID_HANDLE_VALUE (-1)이다. 이런 인터페이스가 뒤죽박죽인 건 윈도우 API의 디자인 결함인 것 같다. memory-mapped file을 만드는 CreateFileMapping의 실패값은 또 NULL임.. -_-;;

또한, 파일과 디렉터리를 구분 없이 찾는 것도 개인적으로 무척 불만이다.
그래서 이 탐색 결과를 담고 있는 구조체에 대해서 dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY 체크부터 꼭 해 줘야 한다.
또한, 이런 디자인으로 인해, 어떤 디렉터리 내부에서 파일은 *.txt 같은 와일드카드로 찾고 디렉터리는 와일드카드 없이 다 찾으려면 검색을 두 번 수행해야 한다. 디렉터리 이름은 언제나 전체 검색이지 이걸 와일드카드로 찾는 일은 오늘날 전혀에 가깝게 없기 때문이다. DIR *.txt /S 같은 걸 구현하는 걸 생각해 보면 쉽게 이해가 될 것이다.

와일드카드를 해석하는 작업은 보통 운영체제가 알아서 해 준다. 하지만 도스와 윈도우는 전통적으로 이 알고리즘이 굉장히 단순하기 그지없어서 * 같은 경우 문자열의 뒤에만 붙일 수 있다. A*T.*P 같은 식의 패턴을 쓸 수는 없다는 뜻.
하지만 프로그래밍 언어나 런타임의 제작사에 따라서는 파일 탐색 기능을 제공하면서 와일드카드 해석은 독자적으로 하는 경우도 있다. 가령, 파이썬은 운영체제의 와일드카드 해석 루틴을 사용하지 않으며, 도스에서 구동되던 DJGPP도 디렉터리 아예 구분자로 \ 대신 유닉스처럼 /를 쓰는 등, 파일 경로 해석 자체를 독자적으로 한다.

이상 파일 탐색 관련 잡설이었다.
파일에서 뭔가 검색, 탐색을 한다고 하면 파일 내부에 있는 특정 문자열을 검색하는 것과, 파일 목록을 추출하는 것, 그리고 열어 놓은 파일 내부에서 읽거나 쓰는 지점을 이동하는 seek가 모두 가능하다.
그리고 특정 파일에 대해서 크기나 날짜 같은 부가 정보를 얻는 기능은, 열어 놓은 파일 핸들을 상대로 수행하는 것과 파일을 열지 않고 수행하는 것이라는 두 양상으로 나뉜다는 특징이 있다.

Posted by 사무엘

2011/07/29 08:32 2011/07/29 08:32
, ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/547

예전에 본인이 글로 쓴 적도 있고, 상식 차원에서 이미 아시는 분도 있겠지만..
프로그래밍 언어마다 문자열을 다루는 방식엔 차이가 존재한다.
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

어지간한 중급 이상 수준의 기능을 갖춘 텍스트 에디터나 워드 프로세서들은 일명 ‘칼럼 블록’ 기능을 제공한다. 아래아한글은 도스 시절부터 ‘구역’이라고 하여 동일 기능을 제공했으며, 단축키는 F4였다. 일반 블록의 단축키는 F3이고 말이다. 마우스로는 그냥 드래그는 일반 블록이고 Alt+드래그가 칼럼 블록으로 통용되고 있다. 칼럼 블록을 만드는 키보드 단축키가 통일되어 있는지는 잘 모르겠다.

칼럼 블록이 일반 블록의 복붙 동작과는 어떤 차이가 있으며 얼마나 유용한지 일일이 구차하게 설명하지는 않겠다. 칼럼 블록은 불연속적인 여러 줄들의 일부를 통째로 선택할 수 있을 뿐만 아니라, 붙이는 동작도 여러 줄에다가 내용을 끼워 넣는 식으로 달라진다. <날개셋> 편집기는 전문적인 에디터를 표방하면서 개발되고 있지는 않기 때문에, 현재 (아쉽게도) 칼럼 블록을 지원하지는 않는다.

그런데 칼럼 블록을 구현할 때 현실적으로 부딪히는 문제가 있다. ‘붙이기’를 할 때 클립보드의 내용이 일반 블록인지 아니면 칼럼 블록인지를 어떻게 판별할 거냐는 것이다.
제일 간단한 방법은 응용 프로그램이 별도의 플래그를 갖고 있는 것이다. 클립보드에다가는 일반 블록처럼 텍스트만 복사해 놓으나, 이 블록이 칼럼 블록이라면 플래그를 켠다. 그래서 붙이기를 할 때 플래그가 켜져 있으면 칼럼 형태로 붙인다.

윈도우 탐색기가 파일을 클립보드에다 복사(Copy)한 것인지 오린(Cut) 것인지 판별할 때도 내부적으로 이런 자체 플래그를 쓴다. 파일은 오려 놓는다고 해서 실제로 파일을 지워 버릴 수는 없으므로, 자체적인 표식밖에는 구분할 방법이 없으니 말이다. 파일의 오리기는 텍스트의 오리기와 다르다. 더 나아가면, 엑셀 같은 스프레드 시트의 오리기도 마찬가지임.

하지만 이 방법을 쓸 경우, 칼럼 블록을 복사해 놓고는 다른 응용 프로그램에서 텍스트를 또 복사했을 때, 그 텍스트도 칼럼 형태로 붙여진다는 문제가 있다. 국산 에디터인 AcroEdit, 그리고 유명한 개발 IDE인 Source Insight가 칼럼 블록을 이런 식으로 구현했고 저런 동작을 보이는 것을 확인했다.
내부 플래그 방식으로 칼럼 블록을 구현했다면, 클립보드 내용이 외부에서 바뀌었을 때 내부 칼럼 플래그를 끄는 기능도 구현해야 할 것이다.

이런 방식 말고, 클립보드 차원에서 아예 자신만이 인식 가능한 별도의 포맷을 등록하는 방법도 있다. 칼럼 블록은 그 포맷으로 복사한 후, 붙이기를 할 때 그 지정 포맷이 존재하면 일반 형식이 아닌 칼럼 형식으로 붙여 넣는 것이다.
물론, 칼럼 블록을 복사하더라도, 다른 프로그램이 내용을 일반 블록 형태로 붙여넣을 수도 있게 일반 텍스트 형식으로도 복사는 해 놓는다.

국산 에디터인 EditPlus, 그리고 MS 비주얼 스튜디오 IDE는 이렇게 칼럼 블록은 별도의 클립보드 포맷을 써서 복사해 놓는 것을 확인했다. 이렇게 하면 칼럼 블록을 오로지 자기 프로그램에서 생성한 클립보드 데이터를 통해서만 인식할 수 있기 때문에 앞서 언급했던 오동작이 발생할 여지가 없다.

EditPlus의 식별자는 “EditPlus Column Selection”이요,
비주얼 스튜디오의 식별자는 “MSDEVColumnSelect”이다. 다른 프로그램들은 어떨지 모르겠다.
워드 프로세서들은 어차피 자기네 고유 포맷을 쓰는 게 관행이기 때문에 칼럼 블록만을 위한 고유 포맷을 만들지는 않는 듯하다. (아래아한글과 MS 워드의 경우)

개인적은 생각은, CF_TEXT 같은 것처럼 칼럼 블록을 위한 텍스트도 운영체제 차원에서 표준 클립보드 포맷을 도입하면 좋지 않을까 싶다. 내부적으로 전세계의 수많은 텍스트 에디터들이 자신만의 고유 포맷으로 칼럼 블록을 표현하고 있을지 알 수 없는 노릇이기 때문이다. 그게 제정되면 칼럼 블록도 에디터들마다 공유가 가능할 것이다.

Posted by 사무엘

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

아래 코드를 실행하면 놀랍게도..
입력된 숫자에 대한 팩토리얼 값이 출력된다. 단, 플랫폼은 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

« Previous : 1 : ... 20 : 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : ... 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:
2678230
Today:
314
Yesterday:
2484