« Previous : 1 : ... 134 : 135 : 136 : 137 : 138 : 139 : 140 : 141 : 142 : ... 221 : Next »

Windows API에서 LoadLibrary는 잘 알다시피 자기 프로세스 공간에다가 다른 DLL을 추가로 매핑시키는 매우 중요한 함수이다. 코드 실행이 아니라 단순 리소스 추출만이 목적인 경우, EXE 내지 현재의 기계가 지원하지 않는 다른 아키텍처로 빌드된 모듈을 열 수도 있다.
Windows에서 어떤 모듈(EXE/DLL)은 타 모듈을 말 그대로 자신이 실행되는 로드타임(load-time) 때 곧장 불러와서 여타 DLL에 대한 함수 링킹을 할 수 있으며, 반대로 실행 중인 런타임(run-time) 때 동적으로 할 수도 있다.

로드타임 로딩은 간편하긴 하지만 모듈 파일 이름 이상으로 불러들이고자 하는 디렉터리 위치를 세밀하게 제어할 수 없다. 그리고 모듈이 단 하나라도 존재하지 않거나 해당 파일에 함수 심벌이 단 하나라도 존재하지 않으면 프로그램이 전혀 실행되지 않는다. 그런 예외 상황이 발생했을 때의 제어도 사용자가 전혀 할 수 없기 때문에 프로그램의 유연성 내지 융통성이 떨어진다는 단점이 있다. 내 프로그램의 로드 자체가 실패해 버리니 말이다.

그래서 새 운영체제에 들어있는 API 함수를 쓰긴 하는데, 그 함수가 존재하는지 체크를 미리 해서 구형 운영체제와의 호환성도 유지하기 위해서는.. LoadLibrary와 GetProcAddress를 이용하는 런타임 로딩 기법을 써야 한다. 로드타임 로딩이라면 운영체제가 그 기능을 내부적으로 자동으로 제공해 줬을 텐데 런타임 로딩은 함수 포인터를 수동으로 관리해야 하니 좀 번거롭긴 하다.

이럴 때, 비주얼 C++ 6때부터 도입된 delay-loading은 로드타임 로딩과 런타임 로딩의 장점을 취합한 굉장히 괜찮은 대안이 될 수 있다. COM은 런타임 로딩을 규격화된 인터페이스라는 형태로 좀 더 깔끔하게 정형화한 바이너리 표준일 테고 말이다.

DLL을 불러올 때, LoadLibrary에다가 파일의 절대 경로를 주지 않고 파일 이름만 달랑 넘겨 주면 이 함수는 프로그램이 실행된 current 디렉터리, 프로그램이 존재하는 디렉터리, 운영체제의 시스템 디렉터리, PATH에 등록된 디렉터리 등 다양한 순서대로 파일을 탐색한다. 로드타임 로딩 때도 대상 DLL은 이런 순서대로 탐색된다.

이것은 프로그램의 동작에 유연성을 부여하고 한 DLL을 여러 프로그램들 사이에서 최대한 쉽게 공유가 되게 하기 위함이나, 오늘날에 와서는 이런 정책은 보안에 악영향을 끼치게 되었다. 이름만 같고 우선순위가 더 높은 디렉터리에 존재하는 악의적인 DLL이 잘못 선택되어 로딩될 수 있기 때문이다. 또한 하위 호환성이 지켜지지 않는 시스템 DLL이 덮어써짐으로써 DLL hell 같은 고전적인 문제도 야기될 수 있다. 갈수록 난잡해지고 포화 상태로 치닫는 시스템 디렉터리는 큰 골칫덩어리이다.

LoadLibrary의 디렉터리 탐색 방식 자체를 바꿀 수는 없다. 그 방식에 의존하여 동작하는 수많은 기존 프로그램들과의 호환성을 유지해야 하기 때문이다. 그렇기 때문에 오늘날 마소에서는, 새로 개발되는 프로그램에서는 LoadLibrary를 호출할 때 저런 알고리즘에 의존하지 말고 반드시 DLL의 전체 경로를 명시해 줄 것을 권고하고 있다. 또한, 전면 금지하는 건 불가능하겠지만, 운영체제의 시스템 디렉터리에다가는 가능한 한 자기 싸제 DLL을 집어넣지 말 것을 권고한다.

일례로, 예전에 qt 라이브러리를 DLL 링크한 프로그램을 돌려 봤다. 이 DLL은 운영체제의 시스템 디렉터리에 있는 것도 아니었는데 어떻게 DLL을 찾는지 궁금했는데... 에구, 그냥 PATH 지정이더라. 운영체제의 환경변수를 대놓고 바꿔 버리는 건 굉장히 안 좋은 방법인데 어쩔 수 없다. 이제 윈도 XP가 나온 지도 10년이 넘었으니 WinSXS 매니페스트 방식이라도 써야 하지 않나 싶다.

요컨대 Windows는 (1) 제3자 응용 프로그램이 자기끼리 공유하는 공용 DLL을 손쉽게 찾아 로딩하는 법, 그리고 (2) 운영체제의 시스템 DLL을 보안 문제 없이 간편히 로딩하는 법을 완전히 이원화하여 체계적으로 제공할 필요가 있다. 확장 버전인 LoadLibraryEx 함수에라도 그런 기능을 좀 추가할 수 없나 궁금하다.

(1)의 경우 아까도 말했듯이 delay-loading이나 WinSXS가 그럭저럭 해결책이다. 이게 중요한 문제이기 때문에 윈도 XP부터는 SetDllDirectory 함수가 추가되긴 했으나, 이것은 로드타임 로딩을 제어할 수 없기 때문에 여전히 근본적인 해결책이 아니다.

(2)는 known DLL 리스트라는 게 레지스트리에 존재한다. 그래서 "kernel32", "user32" 같은 건 DLL계의 예약어(reserved word)처럼 돼서 주변에 kernel32.dll, user32.dll 같은 동일 명칭의 사칭 파일이 있다 해도 언제나 운영체제의 시스템 디렉터리에 있는 놈이 로딩된다는 게 보장된다.

그러나 개인적인 생각은 그걸 API 차원에서 좀 더 엄밀하게 했으면 좋겠다. 아까 말했듯이, API 하위 호환성 유지를 위해 운영체제의 시스템 DLL을 수동으로 로딩하는 경우는 빈번하게 존재한다. 그리고 운영체제가 버전업되면서 새로운 시스템 DLL이 앞으로 얼마나 더 추가될지 모른다. 그러니 오로지 시스템 DLL만 로딩하고 다른 싸제 DLL은 유사품이 있다 해도 거부하는 명령이 있었으면 좋겠다.

앗싸리 시스템 DLL까지 몽땅 시스템 디렉터리 전체 경로를 지정해 줘서 로딩시켜 보기도 했다. 그런데 이렇게 했더니 한 가지 복병에 걸리는 게 있다. 바로 comctl32.dll이다.
얘는 WinSXS 매니페스트로 넘어가서 길고 이상한 다른 디렉터리에 있는 놈이 로딩되기 때문이다. 이걸 무시하고 운영체제 시스템 디렉터리에 있는 놈을 로딩하면 TaskDialog처럼 공용 컨트롤 6.0 이상에서만 지원되는 기능들을 사용할 수 없다.

그러니 시스템 DLL은 경로 다 생략하고 그냥 "comctl32", "kernel32" 이렇게만 로딩하는 게 정답인 듯하다.
문득 스프레드 시트 프로그램인 엑셀이 생각난다. 엑셀은 구조적인 이유로 인해 이름이 동일하고 서로 다른 디렉터리에 존재하는 여러 파일을 동시에 열 수 없다. 수식에서 다른 워크시트 파일을 참조할 때 디렉터리 대신 오로지 파일 이름만을 토대로 탐색을 하기 때문이다.

Posted by 사무엘

2014/04/27 08:25 2014/04/27 08:25
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/956

1. 수원 역 전동차 추돌 사고

도로에서 신호 대기 중이거나 고장· 정체로 인해 서 있는 앞차를 발견 못 하고 추돌하는 건 흔히 발생하는 교통사고 패턴이다.
그런데 이런 부류의 사고가 철도에도 드물게나마 존재한다.
대표적인 예로는, 왠지 콩스러운 2002년 2월 22일에 발생한 수원 역 전동차 추돌 사고가 있다.

한 서울 메트로(그 당시 서울 지하철 공사) 소속 1호선 전동차가 수원 역 진입을 앞두고, 하행 무궁화호를 먼저 보내 주기 위해 신호 대기 정차 중이었다.
그런데 뒤따라 오던 철도청(코레일 출범 전) 소속의 선로 보수 차량이 짙은 안개와 신호 오독으로 인해 이 전동차를 발견 못 하고 그대로 추돌했다.
그 결과, 차량과 직접 닿은 객차 2량이 탈선+대파되었고, 30여 명의 승객이 경상을 입었다.

여느 철도 교통사고와는 달리, 이건 가해 차량과 피해 차량의 소속 회사가 서로 다르기까지 하다 보니 보상 문제를 두고 양사간 알력다툼이 있었다.
철도청에서는 자사가 보유하고 있는 잉여 중고 전동차만 달랑 넘겨 주는 걸로 배상을 마무리 지으려 했다.
그러나 서울 메트로에서는 피해 객차 중에 차령이 3년도 안 된 새 물건이 있다는 걸 내세우면서 신차 도입에 맞먹는 손해 배상금을 청구했다. 이 의견 대립으로 인해 협상이 제대로 진행되지 않았다고 한다.

나중에 결국은 철도청이 서울 메트로의 요구를 사실상 다 수용하는 걸로 분쟁이 종결되었다. 총 배상금은 일반 자동차 교통사고의 배상하고는 잽도 안 되는 49억 2천만 원에 달했다고..! 참고로 전동차 한 편성이 아니라 한 량의 가격이 10억 원 정도 한다.

근본적으로 그때 전동차에도 웬 신호대기라는 게 있었고 판단 착오로 인해 이런 교통사고가 발생하는 게 가능했던 이유는... 평면교차 때문이었다.
수원에서 경부선 전동차가 회차를 하려면 일반열차 선로를 타넘어야 했다. 자동차로 치면 일종의 U턴과 같다. 이때 일반열차 눈치를 보는 건 필수다.

즉, 수원역은 근본적으로 종점으로서는 상당히 열악하고 위험한 구조였다. 또한 이 병목 지점 때문에 경부선 전동차를 충분히 증차할 수 없었다. 수원에 다 와 가지고는 n분간 지루한 신호 대기...

경부선 전철이 수원에서 천안까지 연장된 게 2005년부터인데, 그보다 앞서 병점 구간이 2003년에 개통했다. 이는 수원에서의 평면교차 지장을 없애기 위해 먼저 시급히 취한 조치였다. 거기는 병점 차량 기지 입· 출고 및 회차 선로가 경부선 본선과 별도의 입체교차 시설로 갖춰져 있기 때문이다.

2. 미전 신호소 열차 충돌 사고

자동차나 비행기의 좌석에는 안전벨트가 있다. 배는 안전벨트까지는 아니어도 그래도 침몰에 대비한 구명 조끼 정도는 승객 수만치 갖춰져 있다. 그러나 열차는 한번에 수백 명 이상의 승객을 대량으로 수송하는 교통수단임에도 불구하고 안전벨트 같은 개인 단위의 구명 수단이 전혀 존재하지 않는다.

그 이유는 철도는 주행 중에 도로와 같은 돌발상황을 고려하지 않기 때문이다. 그리고 설령 장애물이 나타난다 해도 어지간해서는 아무 일 없다는 듯 열차가 그냥 장애물을 밀고 지나간다. 무게 차이가 서로 비교가 되지 않기 때문이다. 승객이 급정거로 인한 큰 위험에 빠질 일이 없다.

그런데 똑같이 길고 무거운 열차와 열차가 서로 부딪치게 되면 이건 그야말로 대재앙이 된다.
관성 때문에 뒤의 객차들이 탈선하여 앞의 객차들을 타고 올라가게 되며, 깔린 객차들은 형체를 알아볼 수 없이 부서지기 때문이다. 이 정도의 사고까지 나면 어차피 안전벨트도 아무 도움이 안 되긴 마찬가지가 된다.

위의 1번처럼 멈춰 있는 열차를 뒷차가 추돌하는 정도가 아니라, 아예 서로 마주 보며 달려오던 열차가 머리끼리 정면 충돌하는 건 자동차로 치면 중앙선 침범 교통사고 정도에 해당한다. 이건 단선 구간에서 폐색 처리가 엉망으로 된 완전 막장 철도에서나 가능한 일인데..

우리나라에서도 그것이 실제로 일어난 적이 있었다.
1994년 8월 11일, 경부선 복선과 경전선이 합류/분기하는 구간에서 대구 발 마산 행 경전선 하행 무궁화호(217열차)와 부산 발 대구 행 경부선 상행 무궁화호(202열차)가 그만.. 정면 충돌했다.
이 사고도 당시 위험한 평면교차 시설에 두 열차가 동시에 진입하면서 발생했다.

우리나라 철도는 좌측통행이기 때문에 서울 방면 상행 선로가 부산 방면 하행 선로의 왼쪽에 있다. 그런데 경전선은 경부선의 서쪽, 즉 왼쪽으로 뻗어 나간다.
따라서 맨 오른쪽의 경부선 하행을 달리고 있던 경전선 하행 217열차는 경전선 마산 방면으로 가기 위해 잠시 경부선 상행을 침범했다가 경전선으로 빠져나가야 했다. 그리고 202는 217이 다 지나갈 때까지 남쪽에서 잠시 기다렸다가, 선로 분기기가 원래의 경부선 직진 쪽으로 돌아온 뒤에 진행해야 했다.

그런데 사고가 발생하던 당시에 202는 무슨 이유에서인지 기다리지 않고 경부선 상행 선로를 그대로 진행했다.
그러나 이때 경부선 상행의 해당 지점은 평상시처럼 서울 방면으로 향해 있던 게 아니라, 217이 지나갈 수 있게 경전선↔경부선 상행↔경부선 하행으로 잠시 행로가 바뀐 형태였다.
이에 202는 상행임에도 불구하고 자기 경로를 벗어나 하행 선로로 역주행을 하게 되었고, 그 결과 경부선 하행 선로에서 마주 오던 217과 충돌해 버렸다. 진짜로 중앙선 침범 사고와 똑같다. (☞ 당시의 MBC 뉴스 보도).

이 사고로 총 4명이 사망하고 200여 명의 승객이 중경상을 입었다.
결과론적으로는 잘못된 선로에 진입한 202의 기관사의 과실이 의심되었으나 현직 기관사들은 거기는 정황상 그런 어처구니없는 실수가 발생할 수 있는 곳이 아니라며 과실 가능성을 일축했다. 그리고 오히려 열차나 선로 시설의 시스템적 오류를 더 의심했다.

하지만 시설 미비 내지 파손으로 인해 기계적인 결함 가능성을 제대로 규명할 수 없었으며, 이례적으로 양 열차의 기관사들도 모두 사망해서 당시 상황을 정확히 증언할 사람이 없었던 관계로, 이 사고는 공식적으로는 '원인 불명'으로 처리되고 말았다.
비행기 추락도 아닌데 철도 사고에서 기관사가 모두 죽는 건 굉장히 이례적이다. 게다가 두 열차가 모두 기관차형 열차가 아니라 무궁화호 디젤 동차(NDC)였고, 기관실이 정말 전방에 노출되어 있었기 때문에 충돌 사고 시에 기관사가 상대적으로 더욱 위험하긴 했다.

지금이야 경부선과 경전선이 만나는 구간은 모두 복선에 입체 교차 형태로 바뀐 지 오래이며, 전철화가 되어서 경전선 KTX까지 다니는 상황이 되었다.

Posted by 사무엘

2014/04/24 08:36 2014/04/24 08:36
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/955

1. 특정 명칭(클래스, 함수, 변수 등등)의 선언지로 곧바로 찾아가기.
(1) 소스 코드에서 cursor나 마우스 포인터가 가리키고 있는 명칭에 대해서는 현재 소속되어 있는 클래스나 namespace 문맥을 감지하여 동작해야 하며, (2) 그냥 임의의 심벌을 타이핑하여 조회하는 기능도 있어야 한다. 둘 다 필요하다.

2. 디렉터리를 불문하고 프로젝트에 있는 특정 파일 이름을 곧바로 타이핑으로 조회하여 파일 열기. 시작하는 단어와 중간에 있는 단어가 모두 지원되어야 한다.

3. 그리고 명칭이 아닌 임의의 문자열을 검색하는 Find in files인데, 다음과 같은 범위에서 모두 가능할 것.
(a) 소스(=번역 단위)든 헤더든 프로젝트에 정식으로 등록돼 있는 파일
(b) 프로젝트에 정식으로 등록은 안 돼 있지만, 등록된 파일로부터 인클루드에 의해 한 번이라도 엮이는 파일들
(c) 프로젝트 파일이 하나라도 존재하는 디렉터리에 덩달아 있는 모든 소스 파일들

즉, 3은 파일 내부의 문자열 검색이고 2는 파일 이름 자체의 검색이다. 2의 경우 일단은 검색 도메인이 (a)만으로 한정이지만, 2도 (b)나 (c)가 옵션에 따라 지원된다면 금상첨화다.

Visual Studio IDE의 경우, 1은 진작부터 인텔리센스 엔진을 통해 지원되어 왔다. 그러나 2는 2012에 와서야 가능해졌으며, 3은 (a)만 가능하다. (c)를 하려면 결국 프로젝트 경로를 수동으로 직접 입력해야만 가능하여 매우 불편함. 프로젝트에 존재하지는 않지만 같은 디렉터리에 있는 파일들을 덩달아 찾아야 할 때도 있는데도 말이다.

물론 (b)는 소스 코드를 컴파일까지는 아니어도 전처리기 수준의 파싱은 해야 구현 가능하기 때문에, 좀 어려울지 모른다. #include를 제대로 처리하려면 프로젝트 차원의 인클루드 디렉터리 관리자가 있어야 하며, 조건부 컴파일뿐만 아니라 인클루드 대상 자체에 대해서도 매크로 상수 전개가 필요할 때가 있으니 말이다.

c/cpp 같은 소스 코드가 그 자체로 온전한 번역 단위를 구성하는 게 아니라, 다른 소스 코드에 또 인클루드되어 쓰이는 경우가 있다. 물론 프로젝트에 등록되지 않은 채로 말이다.
이런 파일은 (a) 형태의 문자열이나 파일명 검색이 되지도 않아 대단히 불편하며, IDE가 구문 분석을 하는 것도 굉장히 복잡하고 어렵게 만든다. C/C++에서 인클루드는 정말 양날 달린 검인 게 실감이 간다.

끝으로 (b)와 관련된 여담 하나 좀 남기겠다.
과거 비주얼 C++ 6 시절엔 프로젝트 파일 리스트에 External dependencies라고 해서, 정식으로 프로젝트에 포함돼 있지는 않지만 프로젝트 파일에 의해 인클루드되는 파일을 대충, 얼추 계산해서 표시해 주는 기능이 있었다. '대충, 얼추'라는 말은 그 동작이 100% 정확하지는 않았다는 뜻이다. 그러던 것이 닷넷으로 넘어가면서 이 얼렁뚱땅 불완전한 기능은 삭제되었다.

그 뒤, 버전이 201x으로 넘어가면서 이 기능은 부활했다. 온전한 컴파일러가 소스 코드를 머리부터 발끝까지 다 분석하면서, MFC와 플랫폼 SDK가 중첩 인클루드하는 수십, 수백 개의 헤더 파일들을 하나도 빠짐없이 정확하게 나열해 주는 무시무시한 기능으로 다시 태어난 것이다. 비주얼 C++ IDE는 변화가 없는 것 같아도 내부적으로 이렇게 변모하고 있다.
모든 파일들의 의존도 정보를 파악하고 있다는 소리이니, 이를 바탕으로 함수 호출 tree처럼 파일들의 include 계층 다이어그램(includes / included by)을 그려 주는 기능은 IDE에 혹시 없나 궁금하다.

Posted by 사무엘

2014/04/21 08:28 2014/04/21 08:28
, ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/954

예수님께서 우시니라

요한복음 11장은 죽은 지 나흘이나 지난 나사로를 예수님이 살리시는 장면이다.
죽은 지 그 정도 시간이 지났으면 시신은 시반이 짙어지고 피는 이미 검붉게 썩어 가며 어쩌면 구더기가 일고 부패가스로 인한 팽창까지 시작되었을 텐데(39절), 물리까지는 아니어도 자연의 수많은 생화학 법칙을 정면으로 거스르는 역변환이 일어났다는 뜻이다. (여담이지만, 갓 죽은 시신에 날파리가 날아오는 데 걸리는 시간과, 교통사고 현장에 견인차가 도착하는 데 걸리는 시간이 거의 비슷하다는 말도 있다. =_=)
 
그런데 그 문맥에서 슬며시 등장하는 Jesus wept(35절)는 영어 성경 기준으로 성경에서 가장 짧은 절이다. 참고로 우리말 성경은 흠정역/한킹을 제외하면 유독 대놓고 '울었다' 대신 '눈물을 흘리더라'라고 돌려 번역되어 있다. 왜 그렇게 됐는지는 모르겠다. 창 50:17 요셉이 울었을 때는 다들 그냥 '울었다'라고 했는데도.
 
이때 예수님의 울음의 의미는 무엇일까?
예수님은 나사로가 죽을 때까지 한참을 고의에 가깝게 지체하다가 현장에 도착했다. 그리고 잠시 후면 그 죽은 나사로를 그분께서 살려내실 것이다.
그런 상황에서 그 울음은 당연히.. "네가 죽다니 아이고 꺼이꺼이" 같은 문상과 추모의 의미라고 볼 수는 없다.
"내가 울었던 건 널 부활시킬 추진력을 얻기 위함이었다"....도 아닐 거다. 성경이 무슨 김 성모 만화냐?

인간적인 면모를 보자면, 예수님 역시 인간의 감정과 연약함을 모두 아셨다(히 4:15). 그리고 복음서를 보면 그분은 온갖 고뇌와 번민에 매여 있는 민초들을 불쌍히 여기셨다는 말이 자주 나온다(마 14:14, 9:36, 막 1:41 등등). 동정심, 즉 compassion 되겠다.

누구 사랑하던 크리스천이 죽었다. 그 사람은 구원받았기 때문에 하늘나라에서 편히 쉬다가 훗날 우리를 다시 만날 것이다. 솔직히 처지만 따지면 우리는 고인 걱정은 전혀 할 필요 없다.
그럼에도 불구하고 크리스천 역시 그 사람이 죽으면 당장은 슬퍼하고 울 수 있으며, 인륜과 예절의 관점에서도 그러는 게 마땅하다. 슬퍼는 하되 단지 "잘 가시오. 곧 만납시다" 수준에서 그치지, 멘붕에 빠져서 "아이고 꺼이꺼이 이제 가면 언제 오나" 이럴 필요만이 없을 뿐이다.

예수님께서 그런 사람들에 대한 연민이 클라이막스에 달해서, 부활 권능과는 별개로 울컥하신 거라는 설은.. 우리에게도 큰 위로를 주며 최소한 해롭지는 않다. 행 9:4-5도 이 설을 간접적으로 뒷받침한다. 예수님은 예수쟁이 크리스천들에 대한 박해를 예수 자신에 대한 박해와 동급으로 간주하셨다. 나도 너와 늘 동고동락한다는 뜻이다.

다만, 그렇다고 해서 요한복음 11장엔 그런 휴먼 드라마스러운 장면만 담겨 있다고 생각해서는 곤란할 것이다.
11장 앞부분을 보면 예수님의 제자나 주변 인물들이 예수님의 말귀를 제대로 못 알아듣고 동문서답을 하는 대화가 유난히도 많이 나온다. 7절부터 16절까지, 그리고 21절부터 24절까지를 보시라. 잠과 죽음을 분간 못 하고, 현세의 부활과 내세의 부활을 분간 못 하고.. 분위기가 심상찮다.

그렇게도 참 생명과 참 부활에 대해서 예수님이 거듭 설명을 해 주셨는데도 예수님을 가장 좋아하고 따르는 가까운 사람들조차 아직 분위기 파악을 못 한다. 물론 현장에 내가 있었으면 나라도 제대로 파악을 못 했을 테니 그 사람들 탓을 할 수는 없다.

예수님의 관심사는 영적으로 저 고상하고 저 높은 곳에 가 있는데 사람들의 관심은 오로지 죽은 사람과 유족, 그리고 "저 용한 의사 선생이 지체하지 않고 조금만 일찍 왔으면 나사로가 살 수 있었을 텐데" 뿐이었던 것이다. 요한복음 11장엔 36절만 있는 게 아니라 37절도 있다. 그 말에 예수님이 또 돌직구를 맞아서 '다시 속으로 신음하셨다'라고 38절은 말한다.

사실 11장 전체의 뉘앙스를 보노라면, 예수님은 나사로를 살리러 가실 때와 살리기 직전, 그리고 살리는 과정에서 아버지 하나님께 드린 기도(41~42절)를 봐도.. 그분 머릿속에는 나사로 유족에 대한 위로보다는 아버지의 일 그리고 자기가 아버지로부터 보냄받은 메시야임을 사람들로 하여금 믿게 하는 일... 정도밖에 주 관심사가 없었다고 봐야 한다.

그러니 이런 관점에서 예수님의 울음의 의미는.. 설령 사람들에 대한 동정과 연민이 가미됐다 하더라도 "너희가 나를 제대로 믿었으면 사람 하나 죽은 것 갖고 그렇게 초조하고 통곡하고 멘붕할 필요도 없었을 텐데, 왜 그렇게 달을 안 보고 달을 가리키는 손가락만 보고 있니 ㅠ.ㅠ 보는 내가 너무 안쓰럽다"도 가미되어야 하지 않을까 싶다.

문상 차원의 꺼이꺼이가 아니며, 믿음 부족에 대한 단순 분노나 책망은 더욱 아니다. 다른 예로, 누가복음이 아무리 예수님의 인간적인 면모를 조명한 책이라고 해도 겟세마네 동산에서의 기도(22:42-44)가 십자가형에 대한 단순한 인간적인 공포가 담긴 거라고 볼 수는 없듯이 말이다.

또한, 구약 성경에서 예수님을 가장 닮은 예표라 일컬어지는 요셉의 울음처럼 말이다. 자기는 진작에 형들의 과거 죄악을 아무 뒤끝 없이 다 용서했는데.. 아버지 야곱이 죽고 나니까 형들이 기껏 한다는 간청이 뭐냐면 우리에게 제발 해코지 하지 말아 달라는 부탁이었다. 이때 요셉이 운 것은 감정적인 슬픔 때문이 아니요, 형에 대한 배신감이나 분노 때문도 아니요, 다른 차원의 연민 때문이었을 것이다.

이런 나의 추론이 맞다면..!
실컷 구원받고 나서도 아직도 구원의 상실 때문에 예수님께 손이 발이 되도록 빈다거나, 대환란 안 겪게 해 달라고, 혹은 대환란 때 고문 안 당하고 고통 없이 단칼에 가게 해 달라고 고작 그런 기도나 한다면.. 우리 역시 아마 요 11:35-38과 비슷한 방식으로 예수님을 괴롭게 하고 울릴 수 있을 것이다. 일종의 영적 적용인 것이다(영적 해석이 아님).

이것이 죽었던 나사로가 살아나는 오묘한 장면, 그리고 그 속에 쏙 들어가 있는 "예수님께서 우시니라"를 읽으면서 우리가 얻을 수 있는 교훈이 아닐까 한다.

Posted by 사무엘

2014/04/18 08:30 2014/04/18 08:30
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/953

Windows API에는 FreeLibraryAndExitThread라는 함수가 있다.
얘가 하는 일은 이름이 암시하는 바와 같다. 주어진 모듈에 대해 FreeLibrary를 한 뒤 ExitThread를 호출하여 지금 실행 중인 자기 스레드를 종료한다.

어지간하면 응용 프로그램이 두 함수를 차례로 직접 호출해 주면 되며, 둘을 나란히 호출해야 할 일 자체도 실무에서는 매우 드물다. DLL을 제거하는 건 대체로 응용 프로그램이 종료될 때 같이 행해지지, 특정 스레드의 실행이 끝나자마자 칼같이 행해지는 일은 없기 때문이다. 그런데 왜 이런 함수가 정식으로 별도로 제공되는 걸까(Windows NT 3.1 첫 버전은 아니고 3.5에서 추가됨)? 다 이유가 있기 때문이다.

어떤 DLL이 별도의 스레드를 생성해서 자신의 코드를 동시에 실행하고, 실행 후에는 자기 자신을 스스로 깔끔하게 제거하여 사라지게 설계되어 있다고 치자. 즉, DLL을 로딩한 모듈이 그걸 수동으로 따로 해제하는 게 아니라, 그 DLL이 자기 임무를 다한 후 스스로 사라진다는 것이다. 이건 비록 흔한 디자인 형태는 아니지만 말이다.

이 경우, DLL의 코드가 자신에 대해서 FreeLibrary(hMyDLL)을 함부로 호출해 버려서는 곤란하다. 그러면 자기 스레드가 활동하던 모듈이 메모리에서 사라져 버리기 때문에 그 다음에 실행될 스레드 실행 종료 부분에 해당하는 코드(return 0 내지 ExitThread)까지 사라진다. 스레드는 정상적으로 종료되지 못하고 곧장 access violation이 발생한다.

그렇다고 ExitThread를 먼저 호출하면? 이 DLL을 실행하는 주체인 스레드의 실행이 끝나 버리기 때문에 FreeLibrary가 호출될 기회가 없다. 마치 실행 중인 EXE 자신을 제거하는 코드를 실행하는 것과 비슷한 맥락의 딜레마가 발생한다.

모듈(공간) 해제와 스레드(시간) 종료가 동시에 행해져야 할 경우, 이것은 운영체제가 알아서 동시에 수행해 줘야 한다.
FreeLibraryAndExitThread를 호출한 경우, 내부적으로 FreeLibrary가 됐더라도 그 다음으로 ExitThread를 호출하는 코드는 그 DLL이 아니라 운영체제가 책임을 지기 때문에 안전하다.

한편, Windows에서는 EXE나 DLL의 로딩이 파일 자체를 가상 메모리 주소에다 곧장 연결하는 memory-mapped file 기법으로 행해진다. 그렇기 때문에 실행 중인 프로그램 파일이 중간에 지워지는 것은 운영체제가 허용하지 않는다. 즉 DLL과 스레드 문제로 비유하자면 FreeLibrary 단계에서 이미 실패한다는 것이다.

그렇다고 자신을 먼저 종료해 버리면 자기 자신 파일을 지우는 코드가 실행되지 못할 테니, 이 역시 동시에 충족될 수 없는 모순이 된다. ExitProcessAndDeleteFile 같은 전용 함수라도 있어야 할 것 같은데.. Windows API에는 그런 건 없다.

다만 EXE와는 달리 실행 중인 배치 파일은 자기 자신을 제거하는 게 가능하다. 그래서 설치 제거 프로그램 같은 데서는 내부적으로 EXE를 지우고 자기 자신도 삭제하는 배치 파일을 만들어서 이걸 내부적으로 실행한 뒤, 자기 프로그램은 최대한 신속하게 종료함으로써 흔적 없는 '자폭'을 한다. 배치 파일은 당연히 IF EXISTS와 GOTO loop가 있어서 파일이 완전히 지워질 때까지 삭제 시도를 반복한다.

배치 파일은 자가삭제가 가능하긴 하지만 삭제된 뒤의 명령들은 실행되지 못하고 에러와 함께 실행이 끝난다. 옛날에 4DOS 같은 MS-DOS 대체 명령 프롬프트에는 BTM (Batch to memory)처럼 모든 내용을 메모리로 읽은 뒤에 실행하는 특수한 배치 파일이 있긴 하지만 이것은 MS 기반의 오리지널 셸에 있는 기능은 아니다.

물론 설치/제거 프로그램이라면 요즘은 직접 짜는 게 아니라 Windows Installer를 사용하는 게 대세이니 저런 꼼수를 직접 구현해야 할 필요는 더욱 없어지긴 했다. 자기 정체를 요리 조리 교묘하게 숨겨야 하는 악성 코드나 돼야 필요할까?

거의 모든 Windows API 함수들은 뭘 실행하더라도 성공/실패 여부를 되돌리는 리턴값이 있다. 리턴값이 없는 void형 함수는 정말 실패를 절대로 걱정할 필요가 없는 예외적인 물건을 제외하면 매우 드물다.
그러나 ExitProcess 내지 ExitThread처럼 뭔가 자신의 실행을 종료하고, 실행 후에 리턴값을 받을 주체 자체가 없어지는 함수라면 리턴값이 응당 void이다. 종료하는 동작이 실패할 리도 없을 테고 말이다.

FreeLibraryAndExitThread도 예외가 아니다. 모듈 핸들을 잘못 줄 경우 FreeLibrary 부분은 실행이 실패할 수 있지만, 후반부의 ExitThread 부분은 언제나 성공이 보장되기 때문이다.

그러고 보니 메시지 큐에다가 WM_QUIT를 넣어 주는 PostQuitMessage도 종료와 관계가 있는 전용 함수이며 void 형이다. WM_QUIT 메시지는 GetMessage 함수로 구성된 message loop을 끝내는 역할을 하며, 윈도우 프로시저를 통해 전달되지는 않는다.
MSDN은 저 메시지는 반드시 PostQuitMessage라는 전용 함수를 통해서(주로 메인 윈도우의 WM_DESTROY 타이밍 때) 넣어야지, 수동으로 PostMessage(hWnd, WM_QUIT, 0, 0) 같은 식으로 넣어서는 안 된다고 명시한다.

사실 저건 특정 윈도우가 대상이 아니라 스레드의 메시지 큐 자체가 대상이기 때문에 hWnd에 아예 NULL을 주거나, PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0, 0)과 비슷하다.
다만, WM_QUIT은 여느 메시지와 동일하게 취급되는 게 아니라 스레드의 내부 상태 차원에서 종료 플래그가 붙은 것으로 특수하게 처리되기 때문에 PostQuitMessage 같은 별도의 함수가 존재하는 것이다. 제거 딜레마의 해결 필요 때문은 아니다.

Posted by 사무엘

2014/04/15 08:25 2014/04/15 08:25
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/952

칼빈주의와 알미니안주의

  • 구원받았다면서 행실에 변화가 없는 사람이 왜 이리 많나?
  • 거짓/페이크 영접 기도로 인해 양산된 거짓 구원 확신, 가짜 크리스천에 대한 트라우마
  • 신이 어떻게 자기가 창조한 인간을 지옥에 보낼 수 있나? 그리고 구원받지 못한 사람이 왜 이리도 많나?
  • 신이 존재한다면서 정작 세상엔 신이 존재하지 않는 것처럼 왜 이렇게 악이 가득하나?

등등의 이유로 인해, 세상에는 일명 “예수천당 불신지옥”이라는 이분법으로 설명하기 곤란해 보이는 상황이 무척 많다.
그렇다 보니 이 모순을 풀려고 결국 크리스천들은 마치 좌· 우파마냥 내부적으로 크게 두 극단으로 갈라지게 되었다.

a. 사람마다 구원 여부는 우리의 행위와는 아무 상관 없이 애초에 다 정해져 있다. 이런 하나님의 주권적인 예정에 대해 인간이 감히 왈가왈부할 수는 없다.

vs

b. 아무래도 예수님을 입으로만 믿고 시인하는 걸로는 부족하다. 죄로부터 완전히 회개한 뒤에 자발적인 선행이 뒤따라야 구원받을 수 있으며 이미 받은 구원도 이를 통해서만 유지할 수 있다.

a는 흔히 칼빈주의, 예정론이라고 불리며 b는 알미니안주의라고 불린다. 그러나 이들은 궁극적으로는 둘 다 비성경적인 양극단이다.

1.

예정론의 매우 큰 문제는 '하나님이 원하시는 뜻'과 '하나님이 그냥 허락하시는 뜻'을 완전 혼동하여, 죄를 무슨 죄인 역할극 정도로 만들어 버린다는 것이다.

히틀러가 유대인들을 학살한 것도, 이북의 김씨 부자가 인민들을 학살한 것도 다 하나님이 그렇게 예정해 놨기 때문에 그리 된 거라니 이런 신성모독적인 발상이 어디 있는가? 그런 신을 우리가 어떻게 사랑과 공의가 충만한 하나님으로 믿을 수 있겠는가?

죄가 역할극이라면 예수님의 죽으심과 부활도 아무런 찬양받을 가치가 없이 그냥 짜고 치는 고스톱마냥 역할극에 불과할 것이다. 불이 영원히 꺼지지 않는 뜨거운 지옥도 무슨 가상 머신 매트릭스 샌드박스에 지나지 않을 것이다.

하나님의 주권 하에서 천차만별 불공평한 듯이 배분되는 것은 이 세상에서의 일시적인 지위나 위상뿐이다. 그래서 미국에서 태어나는 애와 북한에서 태어나는 애의 인생이 갈리고, 순교하는 신자와 기적적으로 살아나는 신자의 인생이 갈린다. 사람마다 신분과 빈부귀천이 갈린다.

그러나 개인의 구원 여부는 그런 것과는 전혀 관계가 없다! 하나님은 인간에게 정말로 필요한 것에 대해서는 철두철미하게 공평하다. 송명희 시인의 <나> 기억 안 나냐?
예정되어 있는 것은 구원받은 성도의 향후 지위 그 자체뿐이다. 미리 아심(read-only)을 예정(write operation)과 혼동해서는 안 된다.

가령, 성경의 파라오는 재앙을 자초하지 않고 이스라엘 백성을 순순히 풀어 줬어도 충분히 하나님께 영광 돌릴 수 있었다. 그럴 가능성이 거의 없겠지만, 인간 백정 인간 악마라 불리는 북한 김 정은이라 해도 어느 날 갑자기 회개하고 예수님을 영접한다면 그는 얼마든지 구원받을 수 있다. 당연한 말 아닌가? 예수님의 보혈은 말 그대로 모든 사람에게 유효하기 때문이다.

요컨대 인간이 예수님을 영접하거나 거부하는 것은 철저히 개인의 자유 의지에 달려 있다. 구원이 아무리 대가 없이 행위 없이 주어지는 선물이라 해도, “저 구원받고 싶습니다.”라고 말하고 손을 내미는 것조차 선물 받는 것에 대한 대가라고 얘기하지는 않는다. 인간은 스스로 의로워지거나 자신을 구원할 수 없지만, 스스로 예수님을 영접조차 할 수 없을 정도로 타락하지는 않았다.

저항할 수 없는 무조건적인 은혜는 스스로 선과 악을 분간 못 하는 어린아기가 받는 특례 구원에나 적용되는 조항일 것이다. 또한, 그 하나님의 은혜를 거부하고 자발적으로 지옥에 가는 사람이 있는 것은 하나님의 사랑이나 공의, 전지전능과는 전혀 별개의 영역에 있는 현상일 뿐이다.

난 정말,
하나님이 공의롭거나 전지전능하지 않고 새디스트여서 사람을 지옥에 보내는 것하고,
하나님이 공의롭고 전지전능하긴 한데 일부만 사랑하고 택했기 때문에 열외된 사람을 지옥에 보내는 것하고..
둘의 차이를 도무지 이해하지 못하겠다.

이건 마치 벌거벗은 임금님을 보고, 멍청한 사람에게는 안 보이는 아주 멋진 옷을 입고 있다고 둘러대는 것만큼이나 말장난에 지나지 않는다. 사람의 자유의지를 빼고서 지옥을 설명하면 그 무슨 수를 쓰더라도 하나님의 성품을 왜곡하지 않을 수 없는 모순에 빠진다.

여담이지만, 성경에서 하나님이 누구를 죽이기로 작정하시고 그의 마음을 더욱 강퍅하게 하고 뭐 어쩌기로 하신 것은, 일종의 가속(acceleration)이다. 그 사람을 보호하지 않고 그가 극단으로 치우치고 스스로 막장으로 빠지게 내버려 둔 것에 가깝다. 사람이 자기 힘으로 자동차나 비행기의 무거운 조향타를 움직일 수 없어서 파워스티어링 유압의 도움을 받는데, 하나님의 역할은 그런 유압인 것이다. 사람이 조향 자체를 무슨 pre-programmed된 로봇 조종 받듯이 하는 건 아니다.

2.

한편, 칼빈주의의 반대편에 서 있는 극단도 문제가 많기는 마찬가지다. 이건 믿음을 통해 은혜로 얻는 구원 교리를 아예 대놓고 부인하면서 기독교의 근간을 흔들기 때문이다. 구원의 결과로서 나오는 선행을 구원의 조건으로 혼동하여 이런 오류가 생긴다. 영어로는 fruit / root of salvation이라고 표현한다.

행위가 덧붙은 구원 획득 내지 구원 유지 교리는 성경이 말하는 구원이 뭔지 모르고 하나님이 원하시는 선행의 수준이 뭔지도 모르는 극도의 무지의 소치이다. 어떤 사람이 예수님 영접 기도를 이런 식으로 한다고 생각해 보아라.

“예수님, 저는 내가 죄인임을 이제야 알게 됐습니다. 그래서 죄악된 삶을 모조리 청산하고 예수님을 나의 주님으로 영접합니다. 이제 예수님이 사랑하는 것만을 사랑하고 예수님이 미워하는 것을 미워하기로 결단했습니다.
술, 담배, 마약 다 끊고 예전의 일체의 방탕하던 생활 방식을 다 그만뒀습니다. 예수님을 따라 성결하게 살기 원합니다. 그러니 저를 구원해 주시옵소서. 아멘.”

정말 끔찍하지 않은가? 자기가 예쁜 짓 해서 들어갔다가, 심한 사고 치거나 나쁜 짓 하면 짤리고... 저런 식으로 믿을 거면, 예수 믿는 게 부처· 마리아를 믿거나 심지어 철도교에 입교하는 것과 차이가 도대체 무엇이냐?

선행이 결과론적으로 아무리 좋게 보인다 하더라도, 이런 교리의 누룩은 우리가 극도로 경계해야 한다.
술· 담배, 마약이 나쁜 줄은 솔직히 불신자도 다 알고 그런 건 자기 깜냥과 재량껏 끊을 수도 있는 것들이다. 그걸 그만뒀다는 게 하나님 앞에서 도대체 뭐가 대수란 말인가?

자기가 구원받아야 하는 죄인임을 알았으면, 그 다음에 구원을 요청하며 따라야 할 고백은 이것밖에 없다.
예수님이 나를 위해 나를 대신하여 내 죄값을 치르고자 십자가에서 피흘려 죽으시고 부활하셨다는 걸 믿습니다.” (단, 정말 진심으로 말할 것).

인간의 깜냥으로는 도저히 처리가 불가능한 나의 처참한 죄를 사하기 위해서, 공자· 맹자나 부처나 마리아가 아니라 2000여 년 남짓 전에 이스라엘 땅에 있었던 그 역사 인물인 예수 그리스도가 십자가에서 죽으셨다고 시인하는 게 참 회개이고 기독교의 구원 조건이다!

그리고 사람이 그 구원부터 받은 뒤에야, 물리적인 죄로부터의 진정한 회개를 촉구하는 원동력은 성령님에 의해 차차 생겨난다. 철도는 교통 체증으로부터나 구원할 수 있지 죄로부터 인간을 구원하지는 못한다. 예수님 말고 다른 사대성인 같은 걸 이런 식으로 믿는다고 해서 성령의 열매 같은 게 생기지는 않는다.

그 구원은 나를 담보로 유지되는 게 아니라 하나님을 담보로 유지되는 거다. 내가 선행으로 구원받은 게 아닌 것만큼이나 내 악행으로 구원을 잃지도 않는다. 이게 바로 기독교와 여타 종교와의 넘사벽 급의 차이인 것이다.

구원 절차가 달랑 '믿음' 하나밖에 없고 너무 간단하고 쉬워서 문제라고 생각하는 분들은 그 '믿음'이란 게 뭔지를 아직 잘 모르는 경우가 태반이다. 그래서 자꾸 '행위'를 갖다 붙일려고 하는 것이다. 행위가 전혀 필요하지 않음에도 불구하고, 정말 저렇게 제대로 믿으면서 구원받은 사람이 이 대한민국에 얼마나 될 것 같은가?

물론, 정말 구원받았는데도 엄청 육신적인 신자도 있고 회개의 열매가 보이지 않는 신자도 있다. 신자의 영적 성장은 아주 느리고 답답하고 많은 시행착오를 겪는 과정이다. 행실만으로 사람의 구원 여부를 판단하기란 몹시 어렵다. 예수님의 재림 시기를 알 수 없는 것만큼이나 이것은 우리에게는 일면 불리한 면모이다. 그것만 바로 알 수 있으면 교회에서 불순분자를 훨씬 더 수월하게 솎아 내고 각종 분쟁도 시스템의 힘만으로 예방할 수 있을 텐데 말이다.

그러나 그런 불편을 못 참겠다고 신자들을 거짓 교리로 겁주고 협박하는 건 목사가 해서는 안 될 일이다. 사람이 먹는 음식을 갖고 장난을 쳐서는 안 되듯, 혼의 구원과 관련된 교리로 장난을 치지는 말아야 한다.

3.

믿음과 행위 사이에 모순처럼 보이는 관계 문제는 크리스천 사이에서 영원히 사그라들지 않는 논쟁거리로 남을지 모른다. 어찌 보면 답이 분명히 나와 있는 아주 쉬운 문제인데, 그걸 모순이 많은 이 현실에 적용하기가 껄끄럽기 때문일 것이다.

이것은 “성경에 어떻게 '없음'이 있지? 완전한 성경이 지금 우리에게 있는가?” 만큼이나 매우 중요한 사항이므로 크리스천이라면 이 문제에 대한 바른 관념도 갖추어서 내가 도대체 예수님의 어떤 면모를 믿고 있는지를 잘 따져 봐야 할 것이다. 그렇지 않으면, 당신이 믿는 종교는 인간에게 불가능한 것을 요구하느라 논리적으로 빼도 박도 못할 치명적인 모순에 빠져 있는지도 모른다. 그렇게도 절대무오하다는 성경은 이 문제에 대해서 과연 무엇을 말하고 있겠는가?

본인은 '인간의 자유 의지'와 '오로지 믿음'이 모두 반영되어 있는 위와 같은 해석이 성경적으로 가장 바람직하다고 제시하며, 이 모델로 속 시원히 풀리지 않는 의문은 참고 기다리면서 지켜봐야 한다고 생각하는 바이다.

그런데 무척 재미있는 것은 극과 극은 서로 통하기도 한다는 점이다. 그렇게도 은사주의와 거짓 영접 기도를 비판하면서 선행과 회개를 강조하는 폴 워셔 목사의 경우, 개념상 골수 알미니안주의일 것 같은데 실은 칼빈주의자이다. 아무나 구원받는 게 아니라는 주권 구원이 결국 행위 구원이나 다름없게 되는 셈이다. 계산 과정은 다르지만 궁극적인 결과는 일치한다고나 할까. 이 점도 우리는 곰곰이 생각할 필요가 있다.

Posted by 사무엘

2014/04/12 08:12 2014/04/12 08:12
, , , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/951

추억의 옛날 차들

하루는 인터넷을 돌아댕기다가 심히 놀라운 사진을 발견했다.

사용자 삽입 이미지

오 세상에~! 바로 이거다. 내가 초딩이던 시절, 1990년대 초반까지만 해도 이런 이상하게 생긴 자동차가 시골이나 공사장 같은 데에서 종종 굴러다니고 있었다.
경운기 엔진에다 미군 지프 폐차 부품을 얹어서 급조한 소형 트럭. 일명 딸딸이 혹은 '영운기'라고 불렸나 보다. 어떤 건 짐받이를 들어올리는 '덤프' 기능도 있었다.

외형과 덩치는 군용 지프와 기아 세레스(과거 기아 자동차에서 생산한 사륜구동 1톤 트럭)를 짬뽕한 듯하다. 개인 작품인지, 아니면 어느 기업에서 이런 물건을 만들었는지 알 길이 없다. 옛날에 시발 자동차도 따지고 보면 이런 식으로 부품을 조립해서 만들어지기도 했을 테고.

난 실물을 본 적이 없는 삼륜차도 알고 있는데, 정작 실물을 본 적도 있는 영운기는 21세기 이래로 내 머리에서 존재감이 15년~20년 가까이 완전히 잊혀지고 봉인되어 있었다.
그랬는데 이 사진 덕분에 기억이 순식간에 싹 되살아났다. 너무 반갑다.

영운기는 등록증도 번호판도 없고 각종 세금이나 보험이 붙은 정식 자동차가 아니다. 그렇게 할 필요도 없는 것이, 겨우 저런 허접한 물건이 대포차로 둔갑해서 범죄에 악용되기라도 할 가능성은 0이나 마찬가지니까..
경운기 엔진이 최고로 돌아 봤자 단기통에 출력도 10마력대에 불과한데 힘과 속도가 얼마나 나오겠는가? 그래도 얘는 동력비를 조절해서 순수 경운기+트랙터보다는 빠르게 최대 시속 50~60km까지는 달렸다고 한다.

참고로 경운기의 엔진은 일반 자동차용 디젤 엔진보다 공기 압축비를 더 높여서 작은 덩치와 저회전 상태로도 성능과 연비를 더욱 무리해서 짜낸 형태이다. 농기계는 기름 덜 먹고 경제적이면 장땡이지, 필요 이상으로 고성능이어야 할 필요는 없으니까..
그 대신 경운기는 바로 그 특성 때문에 일반 자동차보다 털털거리는 소음과 진동이 더 심하며, 시동을 걸기도 더 힘들다고 한다.
다만, 승용차처럼 배터리가 방전되어서 시동이 안 걸린다거나 밀어서 시동을 건다거나 하지는 않는다. 내 기억이 맞다면 뭘 손으로 빙빙 돌려 주면서 시동을 걸었던 것 같다.

자, 이것과 함께 문득 떠오른 추억의 대형 화물차가 있다. 바로..

사용자 삽입 이미지

새한 자동차가 내놓은 8톤 덤프 트럭이다. 혹시 얘 기억하시는 분?
1974년부터 1982년까지 생산되었던 물건이다. 참고로 새한 자동차는 오늘날 한국 GM의 할아버지뻘 되는 기업이다. (한국 GM의 전신은 대우 자동차, 그리고 대우 자동차의 전신이 새한 자동차임) 하지만 이 차의 원형은 이스즈(Isuzu) TX/D 시리즈로, 미국차가 아닌 일본차라고 한다.

내가 이 차를 기억하는 건 엔진룸이 운전석의 아래가 아니라 앞에 돌출되어 있어서 우리나라에서는 군용차가 아니면 거의 볼 수 없는 형태이기 때문이다. 앞에 SMC라는 글자가 적혀 있는 것도 기억한다. 도색은 저렇게 국방색 아니면 파란색 두 종류였던 것 같다.

얘는 1990년대에도 이미 보기가 대단히 힘들어진 올드카였다. 그런데 하물며 2010년대는 어떠하겠는가?
하지만 지금도 극소수 포니가 굴러다니고 있는 것처럼 제주도 포함 일부 벽지에는 '아직도' 새한 트럭이 현역으로 뛰고 있긴 한가 보다. 영화나 드라마 촬영용으로 국내외의 올드카를 대여하는 것도 사업 아이템이 되지 않을까 싶다.

이런 추억을 되살리니 참 훈훈하다. 게임도 페르시아의 왕자 같은 고전을 좋아하고 자동차도 고전...
난 컴퓨터 프로그래밍은 물론이고 철도, 한글 세벌식, 킹 제임스 성경 같은 것도 하나도 까맣게 모르던 시절, 10살도 채 되기 전에는 월간 자동차생활과 승용차 취급 설명서를 읽으면서 자동차에 매달린 채 지냈다.

그 기질은 훗날 컴퓨터를 비롯한 다른 관심 분야들에 밀려서 점차 봉인되었으나, 그 봉인이 2010년도에 들어서 다시 풀렸다.
(1) 일단 철도 때문에 교통수단간의 체계적인 비교 분석이 시작되었고, (2) 실제로 자동차를 운전하는 처지가 되었기 때문이다.
나는 딱히 기계 뜯어보는 걸 좋아하는 공돌이가 아니며, 딱히 자동차가 남자의 로망이고 능력의 상징이어서 그걸 좋아하는 것도 아니다.
단지... 20여 년 전의 옛날 생각이 나서 추억을 회상하는 그 느낌이 좋다.
아주 어릴 때부터 이런 쪽에 관심이 많았기 때문이다.

Posted by 사무엘

2014/04/09 19:37 2014/04/09 19:37
, , ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/950

소프트웨어 GUI 구성요소 중에 콤보 박스는 굉장히 유용한 물건이다.
공간을 적게 차지하면서 리스트 박스의 역할을 고스란히 수행할 수 있으며(비록 다중 선택은 안 되지만)
에디트 박스(입력란)의 역할을 수행하면서, 예전에 사용자가 입력했던 문자열이나 샘플이 될 수 있는 디폴트 값을 곧장 선택할 수 있게도 해 주기 때문이다.

입력란이 없이 선택만 가능한 타입을 Windows에서는 drop list 형태라고 부른다.
일반적으로 콤보 박스에서는 마우스 휠을 굴리거나 상하좌우 화살표를 누르면 선택 항목이 인접한 다른 것으로 바뀐다. 그리고 마우스를 클릭하거나 키보드 F4 내지 Alt+상하 화살표를 누르면 리스트가 화면에도 뜬다. 이것이 표준 동작 방식이다.

그런데 Windows는 이것과 약간 다른 형태의 동작 방식도 지원한다. 일명 extended UI라고 들어 보셨나 모르겠다.
이 모드를 사용하는 콤보 박스는 일반적인 기능은 여느 drop list 콤보 박스와 완전히 똑같다.
그러나 얘는 일단 마우스 휠에 반응하지 않는다. 클릭을 하거나 아래 화살표를 누르면 먼저 리스트부터 나타난다. 그 뒤에야 상하 화살표나 마우스를 이용해서 선택 아이템을 변경할 수 있다.
다른 프로그램들에서 이렇게 동작하는 콤보 박스를 본 기억이 있으신 분 계신가? 이런 콤보 박스는 매우 드물고 보기 힘들긴 할 것이다.

extended UI가 지정된 콤보 박스는 아이템 선택을 바꾸는 게 번거롭다. 굳이 리스트를 꺼내지 않고 간편하게 선택을 바꿀 수가 없으며, 리스트를 여는 키보드/마우스 동작이 반드시 선행되어야 하기 때문이다.
굳이 이런 모드를 왜 넣었는지 본인으로서는 알 길이 없다. 혹시 Windows 3.x 시절에는 콤보 박스가 원래 이렇게 동작하기라도 했었나? 아니면 다른 프로그램의 GUI와 호환성을 유지하기 위해서였는지?

호환성이 이유라면 차라리 모든 콤보 박스들이 extended이든 그렇지 않든 사용자가 지정한 방식으로 동일하게 동작하도록 제어판 설정 같은 걸 추가하면 된다. 굳이 각각의 콤보 상자에 따로 적용되는 옵션으로 둘 필요는 없다.

더구나 extended UI의 사용 여부는 내가 아는 한은 어느 개발 환경에서도 리소스 차원에서 개체 속성의 수정만으로 간단히 지정하는 방법이 없다. 다시 말해 반드시 코딩을 통해서 지정해 줘야 하며, API의 형태도 구리다는 뜻이다. 이상한 점이 아닐 수 없다.

CB_GETEXTENDEDUI 메시지를 보내서 사용 여부를 얻어 오고, CB_SETEXTENDEDUI로 지정하면 된다. 진짜로 BOOL 값 하나를 달랑 얻어 오거나 지정하는 get/set 함수 형태 그 이상도 그 이하도 아니다.

트리 뷰나 리스트 뷰 같은 공용 컨트롤의 경우, 지정할 수 있는 속성이 워낙 많다 보니 운영체제가 기본으로 할당해 주는 스타일과 확장 스타일(extended style)로도 공간이 부족하다. 그래서 자체적인 추가 확장 스타일을 얻거나 지정하는 메시지가 따로 존재한다.

그러나 콤보 박스는 필요한 정보량이 겨우 1비트에 불과하고 그 정도면 그냥 CBS_(EX)_EXTENDEDUI 같은 스타일 비트 하나만 추가하는 걸로 충분하지 않았을까? 안 그래도 잉여력이 충만한 옵션인데 왜 사용하기도 번거롭게 만들어 놓았나 하는 의문이 남는다. 아니... 반대로 잉여로운 옵션이니까 API도 그렇게 따로 뚝 고립시켜 놓은 것인지도?

옛날에는 extended UI를 리소스 에디터에서 속성 변경만으로 곧장 지정했던 것 같기도 해서 지금 비주얼 C++의 리소스 에디터를 뒤져 보고, 심지어 비주얼 C++ 6 같은 옛날 버전들도 살펴봤다. 하지만 그런 건 없다.

그 대신, 비주얼 C++ 4~6이 사용하던 옛날 프로퍼티 대화상자가 사용하는 콤보 박스가 extended UI를 사용하는 것을 확인했다. 마우스 휠이 동작하지 않으며, F4 대신 아래 화살표를 누르면 drop list가 나오더라.
그리고 그러고 보니.. MS 오피스 프로그램들, 특히 대화상자들까지 운영체제의 표준 GUI 대신 자체 GUI를 쓰는 Word와 Excel의 경우, 모든 콤보 상자들이 extended UI 기반이긴 하다.

운영체제의 GUI를 API 날것 형태로 그대로 제공하는 게 아니라 자체적으로 재분류도 해 놓은 닷넷(C#)이나 비주얼 베이직 6의 폼 에디터도 살펴봤다. 콤보 박스를 집어넣었지만 딱히 extended UI 속성을 지정하는 프로퍼티는 보이지 않는다. (단, 델파이까지는 못 살펴봄)

이상, Windows의 기본 GUI에 존재하는 어느 대단히 잉여로워 보이는 기능과 불편한 API에 대해서 살펴보았다.
지금이나 앞으로나.. extended UI가 적용된 콤보 상자는 거의 찾을 수 없을 것이다.
옛날에 노턴 유틸리티의 GUI(뭐, 텍스트 모드에서 GUI를 비슷하게 흉내 내며 동작한 것이니 정확히 말하면 TUI?)가 제공하는 콤보 상자는 Ctrl+아래 화살표를 눌러야 리스트가 떴었는데 Windows는 F4 또는 "Alt+아래 화살표"이구나.

여담을 하나 남기며 글을 맺겠다.
운영체제가 제공하는 각종 Win+? 단축키에 대한 설명은 컴퓨터 활용 팁 같은 데에 많이 소개되어 있다. 하지만 운영체제가 제공하는 기본 컨트롤 자체에 대한 팁 정보는 상대적으로 문서화나 공유가 덜한 것 같다.

예를 들어 복수 선택이 가능한 리스트 컨트롤은 Shift+F8을 눌러서 복수 선택 모드로 진입하게 되어 있는데, 이것 말고도 내가 모르는 기능이 있는지도 모른다. 왜 하필 그냥 F8도 아니고 Shift+F8인 것이며 그 유래는 무엇일까?
그리고 리스트 뷰 컨트롤은 아이템 이름을 바꾸는 단축키가 왜 하필 F2일까? 이런 것에 대해 좀 더 알았으면 하는 생각이 있다.

Posted by 사무엘

2014/04/04 08:31 2014/04/04 08:31
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/948

#define의 대체제

확실히 #define은 다른 걸로 대체 가능할 때는 가능한 한 안 쓰는 게 좋을 것 같다.
C++은 용도별로 다음과 같은 다양한 대체제를 제공한다.

1. 매크로 함수의 대체제: 인라인 함수로 대체 가능하며, 템플릿까지 동원하면 매크로 함수 만만찮은 유연한 메타프로그래밍이 가능하다.
또한 한 함수 안에서만 지엽적으로 반복되는 루틴을 정리하려면 C++0x부터는 람다 함수를 쓸 수도 있다.

2. 매크로 상수의 대체제: 정수의 경우 enum을 쓰면 같은 성격의 여러 심벌들을 한데 묶어 놓을 수도 있어서 좋다.
그리고 문자열은 그냥 const char/WCHAR 형태의 전역/클래스 static 변수로 처리함. 선언과 정의가 따로 존재해야 해서 불편할 수 있으나, 이것은 선언부에다 값을 다 집어넣고 확장 문법인 __declspec(selectany) extern const 를 지정해서 해결할 수도 있다.

아무 통제도 없이 너무 일방적으로 효력이 나타나는 #define보다는 저런 대체제들이 type-safety와 엄격한 scope 검증이 보장되기 때문에 "훨씬 더" 깔끔하다. 가능한 한 전처리기보다는 컴파일러에게 일을 맡기는 게 바람직하다.
내가 만든 명칭이 매크로로 이미 존재하여 딴 걸로 치환되고 있는 줄도 모르고 컴파일러가 자꾸 이상한 난독증을 보이며 에러를 뱉는 것 때문에 빡친 경험이 있는 사람.. 주변에 의외로 많다. ㅎㅎ

단, 그럼에도 불구하고 대체제가 존재하지 않아서 #define을 불가피하게 써야만 하는 경우는 아마도 다음과 같을 것이다.

1. #if #elif #endif 같은 조건부 컴파일 변수 지정

2. 함수 형태를 갖추기조차 민망할 정도로 너무 간단한 로직. 디버그 빌드에서도 독립된 함수 호출이 아니라 언제나 인라이닝이 반드시 보장되기를 바라는 부분

3. 호출하는 함수나 지정하는 변수 이름을 말 그대로 간단히 치환만 시키기를 원하는 경우

4. 대체제의 문법적 한도를 넘는 과격한 구문 치환을 해야 하는 경우. 특히 #나 ## 같은 연산자를 동원해서 완전히 새로운 토큰을 만들어 내야 할 때

5. __LINE__, __FILE__, __TIME__ 같은 빌드/디버그 정보를 그때 그때 삽입하고 싶을 때

6. 정수와는 달리 부동소숫점과 문자열은 여전히 #define이 유용한 경우가 있다.
부동소숫점은 enum이 지원되지 않고 static const 멤버도 클래스 선언부에서 바로 값 지정이 되지 않기 때문이다. (이걸 지원하는 컴파일러도 있긴 하나, 일단은 비표준임)
문자열은 매크로 상수의 경우, concatenate(연결)되는 문자열의 일부가 되는 게 가능하다. const 상수는 그렇지 않다.

#include와 #define이 너무 지저분하고 컴파일 시간을 증가시키는 요인이라며 없애자니.. 위와 같은 용도까지 부정하는 건 현실적으로 무리이긴 하다.

여담으로..
근래엔 남이 만든 코드를 읽다가 IID_PPV_ARGS라는 매크로를 보고 감탄하여 내가 짠 기존 코드에다가도 다 리팩터링을 해서 적용해 놨다.

CoCreateInstance와 IUknown::QueryInterface 때 꼴도 보기 싫던 void ** 형변환을 없애 주는 매우 편리하고 유용한 물건이다. COM이 등장한 건 무려 20년이 넘었고 C++에 템플릿이 추가된 것도 만만찮게 오래 됐을 텐데 이 매크로는 무려 Windows 7의 플랫폼 SDK에서야 정식 등장했다는 게 놀랍다.
매개변수 2개를 하나로 줄이는 역할까지 하니 이 정도라면 컴파일러가 아니라 전처리기 매크로밖에 선택의 여지가 없긴 하다.

Posted by 사무엘

2014/04/01 19:20 2014/04/01 19:20
,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/947

휴대용 자동차

요즘 교통수단이라는 건 사람이 단순히 말 타듯이 위에 타는 형태가 아니라, 안에 들어가서 조종하는 형태를 가정하고 만들어진다. 그렇기 때문에 큼직하고 안에 공간도 제법 있으며, 이걸 또 다른 교통수단에다 싣는 건 거대한 화물선이나 트레일러급이 아니면 일반적으로 가능치 않다. (자전거는 엔진이 달린 '자동차'는 아니니까) 그러니 배는 말할 것도 없고 승용차 정도만 돼도 법적으로 준부동산으로 분류된다.

하지만 컴퓨터도 들고 다니고, 전화기도 들고 다니는 세상에 휴대 가능한 1인용 초소형 교통수단에 대한 연구가 아주 없는 건 아니다. 제트팩도 있는데 하물며 더 저렴한 자동차가 휴대용 버전이 없겠나?
쉽게 생각해 보시라. 막히는 곳에서는 사람이 그냥 차를 들고 성큼성큼 걷다가, 도로가 나오면 다시 차를 펼쳐서 빠르게 이동할 수 있다면,
주차를 따로 하는 게 아니라 차를 접어서 같이 들어갔다가 나오는 게 가능하다면 이 또한 매력적일 것이다.

내가 아는 휴대용 교통수단은 크게 두 가지이다.

1. 일본 마쓰다 자동차에서 여행용 캐리어 정도 크기에 쌀 한 가마니 남짓한 무게의 1인용 휴대용 자동차를 만든 게 있다. 초소형 1기통 2행정 가솔린 엔진으로 최고 시속 30km 남짓을 낸다고. 기발하다.

사용자 삽입 이미지사용자 삽입 이미지

근데 난 저거 굉장히 옛날에, 20년도 더 전에 봤었다. 1990년대, 초등학교 시절에 월간 자동차생활 잡지에서 처음 본 거니까..
내연기관 대신 그냥 전기 모터를 썼으면 더 작고 가볍게 만들 수 있었을 것이다.
전동 휠체어랑 뭐가 다르냐는 질문이 있을 수 있는데, 아무래도 환자가 타는 용도가 아니니까 탑승자가 더 꾸부정하게 불편한 자세로 앉아도 되고, 그만큼 차지 면적과 기계의 크기를 더 줄일 수 있을 것이다.

2. 그리고 최근에 개발된 물건으로는 외륜 오토바이가 있다. 얘는 전기로 달린다.
타이어 폭이 크고 손잡이도 있기 때문에 외발자전거보다야 타거나 중심 잡기는 쉬울 것 같다. 외발자전거 타는 게 취미인 분에게는 무척 흥미로울 듯.

사용자 삽입 이미지

탑승 모습이 좀 스카이 콩콩처럼 생겨 보인다만, 그건 그냥 착시다. ^^

여타 장거리 교통수단에 휴대가 가능하면서 한편으로 자전거보다 오르막을 더 잘 오르고 빠르게 갈 수 있는 편리한 소형 교통수단이 있다면 분명 유용할 것이다.

Posted by 사무엘

2014/03/30 08:27 2014/03/30 08:27
, ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/946

« Previous : 1 : ... 134 : 135 : 136 : 137 : 138 : 139 : 140 : 141 : 142 : ... 221 : Next »

블로그 이미지

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

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/12   »
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 31        

Site Stats

Total hits:
3051542
Today:
2562
Yesterday:
2142