« Previous : 1 : ... 94 : 95 : 96 : 97 : 98 : 99 : 100 : 101 : 102 : ... 230 : Next »

5. 엔진 브레이크

엔진 브레이크라는 건 감속· 제동을 위해 자동차에 따로 장착되는 기계 장치를 가리키는 게 아니다. 이미 있는 엔진의 특성을 이용해서 차의 속력을 슬금슬금 줄이는 일종의 운전 테크닉에 가깝다.
자동차에서 엔진이 돌아가는 것과 바퀴가 돌아가는 것 사이의 관계는 뭐랄까 참 미묘하다. 서로 영향을 주고받는다. 엔진이 돌아가는 것에 비례해서 바퀴가 돌아가지만, 반대로 바퀴가 관성을 따라 계속 굴러가는 것이 엔진을 덩달아 회전시켜 주기도 한다.

엔진 브레이크의 본질은 강제로 기어를 저단으로 바꿔서 바퀴가 굴러갈 때 엔진을 덩달아 회전시키는 것을 굉장히 어렵게 하는 것이다. 그러면 아무리 내리막이라 해도 차가 호락호락 미끄러져 내려가지 않게 된다. 1단으로 고정이라도 시키면 차가 조금만 가속되어도 엔진 회전수가 팍 치솟으면서 굉장히 큰 저항 같은 게 걸린다. 물론 엔진 브레이크를 오· 남용하면 변속기를 포함한 파워트레인 계통이 퍼질 위험이 있지만, 그건 무슨 시속 100에서 1~2단 고정을 시켜서 엔진 회전수가 레드존 이상으로 치솟았을 때에나 걱정할 사항일 뿐이다.

이런 관점에서 보면, 변속기를 D로 놓고 주행하던 중에 가속 페달에서 발을 잠시 뗀 상황은 정말 순수하게 자전거 페달에서 발을 떼고 관성만으로 달리는 것과 같은 상황이 아니다. 정말 순수하게 관성 주행을 하려면 변속기를 N으로 옮기든가, 수동 변속기라면 클러치를 밟고 있어야 한다. 엔진이 바퀴와 연결되어 있는 한 고단 상태라도 아주 약하게나마 엔진 브레이크가 걸려 있는 셈이다.

관성만으로 자동차 바퀴를 굴리고 바퀴와 연결된 엔진까지 돌리는 상태는 오래 가지 못한다. 자동차는 지금 설정된 단의 기준으로 아이들링 rpm에 해당하는 최저 속도까지 서서히 감속될 것이고 엔진 rpm도 비례해서 줄어들 것이다. 액셀을 안 밟고 계속 방치하면 힘이 부족해서 현재의 '단'도 공기 저항 등 여러 이유로 인해 유지되지 못할 것이다. 그러니 자동 변속기는 알아서 더 저단으로 변속을 할 것이고, 궁극적으로 자동차는 최저단인 1단에서 그냥 슬슬 기어가는 상태로 되돌아가게 된다. 단순히 공기 저항 같은 요인 때문에 감속되는 게 아니라 엔진 브레이크가 걸려서 그렇게 된다는 뜻이다.

엔진 브레이크는 브레이크 페달의 부담을 일부 분담해 줄 뿐, 얘 단독으로 차를 완전히 세우지는 못한다. 토크가 작고 회전수 편차가 큰 휘발유 엔진이 엔진 브레이크의 성능이 더 좋은데, 정작 드럼 방식 브레이크 기반이고 엔진 브레이크가 더욱 절실히 필요한 차량들은 디젤 엔진 대형 차량이라는 게 역설적이다.

6. 접지력

브레이크라는 건 동작하기 위해서 충족되어야 하는 매우 기본적이고 중요한 전제 조건이 있다. 바로 바퀴가 제대로 된 접지력을 발휘하는 것이다. 바퀴가 접지력을 상실하면 굳이 급발진처럼 엔진에 의해 속도가 더 붙지는 않을지 몰라도, 핸들과 브레이크가 말을 전혀 듣지 않고 차가 미끄러지기 때문에 매우 위험한 상황에 빠진다.

밥을 먹고 있는데, 식탁 표면에 물이 흘려져 있으면 그 위의 밥그릇이나 반찬 그릇이 가끔 케바케로 미끄러지고 저절로 움직이기도 한다. 그 얇은 수면 위로 설마 부력이 작용했을 리는 없지만 지면 정지 마찰력이 극도로 작아지긴 한 것 같다. 그걸 보고서는 "아! 빗길에서 그 무거운 자동차가 미끄러지는 것도 바로 이런 원리이겠구나" 하는 생각이 들었다. 난 딱히 난폭운전을 하지 않아서 그런지 빗길에서는 차가 물의 저항 때문에 더 잘 안 나아가면 안 나아가지, 딱히 미끄러지거나 한 적은 없었던 것 같다.

일상생활에서 뭔가 도구 차원에서 접지력을 향상시켜서 미끄러짐을 방지하기 위해서는 스노우 타이어와 체인(자동차), 아이젠(등산) 같은 게 쓰인다. 그러고 보니 유리병 뚜껑 같은 게 너무 조여져 있어서 안 따지고 손으로 돌려도 손만 미끄러질 때도, 옷이나 헝겊류를 씌우고 그걸 돌리면 뚜껑이 돌아가서 열리는 경우가 생긴다. 이건 병따개나 손톱깎이처럼 지레의 원리로 토크를 키운 게 아니라, 순전히 접지력을 올리는 좋은 예이다. 회전력만 세다고 해서 장땡이 아니다.

자동차는 밥그릇과 비교했을 때 다소 길쭉한(?) 외형이고, 스스로 굉장한 고속으로 움직이기도 있기도 하다. 그렇기 때문에 진행 방향 기준으로 앞뒤의 무게 분배의 균형도 꽤 중요하다.
핸들을 꺾었는데 미끄러져서 차체가 운전자의 기대보다 더 큰 반경으로 돌게 됐다. 그래도 차가 앞뒤 방향이 유지라도 되면 그건 '언더스티어' 성향이다. 그 반면, 조향 과정에서 차의 뒷부분이 원심력을 감당 못 해 드리프트 하듯이 홱 도는 것은 '오버스티어' 성향이다.

묘기· 곡예 운전을 하려면 이런 차의 특성을 잘 알아야 한다. 갑자기 튀어나온 차량을 피하러 핸들을 갑자기 꺾다가 차의 뒷부분이 덜렁덜렁 요동치는 걸 피시테일(fish tail) 현상이라고 하는데.. 이건 일종의 언더스티어 성향으로 봐야 하나 모르겠다. 흔한 통념과는 달리, 딱히 전륜구동이냐 후륜구동이냐를 가리지는 않는다. 엔진이 실린 앞부분이 더 무거운 자동차라면 언제든 발생할 수 있다.

피시테일 현상에서 벗어나려면 마치 급발진에 대처할 때와 마찬가지로 당장의 직감과는 어긋나는 방식으로 자동차를 조작해야 한다. 브레이크를 밟을 게 아니라 오히려 가속을 해야 한다. 그래야 무게중심이 뒤로 쏠리면서 차량의 뒷부분이 무게를 얻고 불안정한 진동을 멈추기 때문이다. 커브를 돌 때 감속이 아니라 오히려 가속을 하듯이 말이다.

이런 식으로, 자동차의 주행에는 연료를 연소시켜서 그 폭발력으로 바퀴를 굴리기까지 전반적인 과정이 비선형적이고 정량적으로 기술하기 어려운 요소가 많다. 무슨 우주 공간처럼 마찰이고 공기 저항이고 다 없고, 그저 연료를 뒤로 분사해서 곧이곧대로 작용· 반작용대로만 나아가는 거라면 기술하기 참 쉽겠지만 현실은 그렇지 않다는 얘기이다. 타이어의 접지력이라든가, 공기 저항 같은 건 최하 대학에서 기계공학 학부나 대학원 수준이 돼야 다뤄질 것이다.

단적인 예로, 자전거만 해도 차체가 너무 무거우면 처음에 출발할 때 페달을 밟는 게 아니라 그냥 발로 땅을 뒤로 차고 나아가는 게 덜 힘들지 않은가? 그런 게 무슨 원리로 왜 발생하는 차이인지가 단순 경험적인 직감이 아니라 수식으로 아직 좀 알쏭달쏭하다. 완전히 이해를 못 했다.

타이어가 평소에 그렇게도 좋은 승차감을 선사하지만, 바람이 빠지면 완전히 다른 물질로 바뀐 게 아닌가 싶을 정도로 차체를 안 나아가게 만든다. 공기의 있고 없고 차이가 무슨 역학적인 차이를 만들어 내는 걸까?
더 나아가 차체의 무게와 엔진 종류, 배기량, 기어비가 주어졌을 때 그 차의 경제 속도나 최적 연비,  등판능력 한계를 구하는 근거도 내가 이해 가능한 한도까지 알아 가고 싶다.

7. ABS

자동차가 바퀴가 굴러가는 속도(A)와 차체가 움직이는 속도(B)가 일치하지 않게 돼서 좋을 건 전혀 없다. A>B인 건 바퀴가 헛도는 것이고, A<B인 건(심지어 A=0일 수도..) 미끄러지는 것이다. 미끄러지는 현상을 차량 전체의 관점에서는 skid라고 표현하고, 타이어의 관점에서는 잠김(lock)이라고 표현하는가 보다.

ABS란 제동력 자체가 아니라 접지력 향상을 위해서 고안된 안전 장치이다. 수십 년 전까지만 해도 고급차에만 존재하던 값비싼 선택사양이었으나, 2010년대 이후부터는 경차에도 의무적으로 달리는 모든 차들의 필수품이 된 지 오래이다.

얘는 브레이크를 기계의 힘으로 넣었다 끊기를 반복함으로써 접지력의 향상을 도모한다. 즉, 시속 100km 상태에서 150m를 더 나아가야 멈춰설 것을 120m 만에 멈추게 해 주는 게 아니다. 미끄러운 빗길· 빙판길 커브에서 브레이크를 꾸욱 깊게 밟았을 때 차가 전방을 향해 쫘악 미끄러져서 길을 이탈하는 게 아니라, 제동 거리가 얼마가 나오건 커브 틀면서 원래 성능대로 곱게 멈춰서는 것 자체를 도와준다는 뜻이다. 먼저 바퀴가 땅에 제대로 붙어 있어야 그 다음에 핸들이고 브레이크고가 말을 들을 것이기 때문이다.

사용자 삽입 이미지

위의 사진은 ABS가 하는 일을 정확하게 묘사하고 있다. 정말 센스 대박이다~!! ㅋㅋㅋㅋㅋ 한눈에 바로 이해된다.
노면이 미끄러워서 바퀴가 잠기는 현상이 감지되면, ABS는 운전자의 브레이크 동작을 기계적으로 수 차례의 브레이크 밟기+떼기 트레몰로로 구현해 준다. ABS는 anti-lock brake system의 약자이다만, 각종 프로그래밍 언어에서는 절대값을 구하는 함수의 명칭으로 훨씬 더 많이 알려져 있다..;;

굳이 빗길이나 빙판이 아니어도, 고속 주행 중에 그야말로 강한 관성이 느껴지고 타이어의 스키드 자국이 생길 정도로 브레이크를 강하고 깊게 밟으면 ABS가 발동된다. 스키드 자국이라는 게 타이어가 멈춘 채로 차체가 움직여서 타이어가 길바닥에 질질 긁혔다는 뜻이니 말이다.

이때 브레이크를 밟는 발에서 부르르르~ 떨림이 느껴질 것이다. 트레몰로가 연주되었다는 흔적이다. 브레이크를 사뿐히 즈려밟고 부드럽게 정지하는 평상시에는 ABS의 존재를 체험할 일이 없다.
사실, 오늘날은 ABS는 차체 자세 제어 장치(현대 자동차에서 사용하는 용어는 VDC)라는 최첨단 주행 안전 시스템의 일원, 구성원이 되어 있다. 자동차가 운전자가 의도했던 대로 움직이고 있는지, 아니면 미끄러지는 중인지, 어느 방향으로 무슨 가속도가 작용하고 있는지를 몽땅 파악해서 타이어별로 서로 다르게 구동력/제동력을 공급해 주는 경지에까지 도달해 있다.

본인도 옛날에 눈이 내리고 얼어서 빙판이 된 '오르막' 비탈길을 차를 몰고 오른 적이 있었는데... 뭔가 미끄러지겠다 싶은 상황에서 차가 미끄러지지는 않고 그 대신 부르르르~ 떨면서 계기판에는 생전에 본 적이 없는 경고등이 잠깐 켜졌다가 꺼지는 걸 봤다. 나중에 알고 보니 그건 VDC가 동작한 것이었고, 떨림은 VDC의 명령을 따라 ABS가 발동된 흔적이었다.

8. 맺음말: 타 교통수단의 제동 장치

(1) 지금까지 자동차 내지 자전거 위주로 브레이크 얘기를 늘어놓았다만.. 비행기의 랜딩기어 바퀴에도 브레이크가 달려 있다. 애초에 저 ABS도 맨 처음에는 젖은 활주로에 착륙할 때 미끄러지지 말라고 비행기용으로 개발되었다가 나중에 자동차와 철도 차량에도 전해진 것이다.
(여담이지만 안전벨트도 맨 처음엔 비행기를 위해서 개발된 거다. 이건 철도에는 필요 없어서 도입되지 않고 자동차에만 추가로 전해졌지만.. 처음부터 자동차를 위해서 발명된 대표적인 안전 장치로는, 금만 가지 와장창 박살나지 않는 '안전유리'가 있다.)

다만, 비행기는 지상 주행의 비중이 자동차보다 훨씬 작으며, 몇백 명이 타는 대형 여객기라 할지라도 접지 형태는 고작 '삼륜차'에 가깝다..! 그렇기 때문에 브레이크도 뒷쪽 바퀴들에만 달려 있다. 착륙 직후에는 플랩, 스포일러, 엔진 역추진처럼 공기를 직접 맞닥뜨리는 방법으로 속도를 줄이고 또 줄인 뒤에, 바퀴 제동은 기체를 완전히 세우는 결정타로만 사용된다.

비행기 조종석의 페달은 자동차의 액셀/브레이크와는 달리 양발로 조작하며 앞쪽과 뒤쪽의 부위 구분까지 있다. 발꿈치(뒤) 쪽은 비행기가 떠 있을 때 사용하는 방향타이고, 발가락(앞) 쪽은 비행기가 지상 주행 중일 때 사용하는 브레이크이다. 즉, 이륜차처럼 브레이크가 앞뒤 구분이 있는 게 아니라 좌우 구분이 있는 셈인데, 양쪽 바퀴의 제동 정도를 달리함으로써 '조향'을 할 수 있다. 무한궤도 탱크가 방향을 전환하는 것처럼 조향하긴 하지만 추력· 동력 조절이 아니라 제동력 조절이라는 차이가 있다.

(2) 전기로 달리는 차량은 차축을 발전기에다 연결해서 "기왕 제동을 걸 거면 이미 가진 운동량으로 에너지 생산이나 덤으로 하면서 서자"라는 발상을 실현한다. 이것도 방법이 한 가지만 있는 게 아니어서 '발전 제동'과 '회생 제동'이라는 메커니즘이 있다.

역에 정차할 때 전동기 인버터에서 나는 소리가 가속 구동음의 역순으로 주파수가 올라갔다 내려가기를 반복하는 것들이 있다. 이건 개념적으로 자동차의 단을 단계적으로 낮추는 거나 다름없는데, 일종의 엔진 브레이크이기라도 하나 하는 생각도 든다.
그나저나 1세대 KTX(떼제베)는 내부적으로 제동을 어떻게 하는지, 역에 정차할 때 여느 절도 차량에서도 들을 수 없는 시끄러운 굉음이 나는 걸로 악명 높다. 좀 개선이 필요한 점으로 보인다.

(3) 엘리베이터 중에도 한 30층 정도 되는 고층 건물에서 운행되는 초고속 엘리베이터는 브레이크가 있다. 도착층의 3~4층 전부터 이미 감속하는 게 느껴질 정도인 엘리베이터는 우리가 흔히 탈 수 있지는 않아 보인다.

Posted by 사무엘

2018/04/04 19:32 2018/04/04 19:32
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1475

* 예전에 썼던 글을 내용을 보충하여 리메이크 한 것이다.

1. 들어가는 말: 자전거의 브레이크부터

육해공의 모든 교통수단들은 가속 장치만 있는 게 아니라 제동 장치도 어떤 형태로든 갖추고 있다. 어찌 보면 잘 가는 것보다도 제때에 잘 서는 게 더 중요하기 때문이다.

제일 간단한 교통수단인 자전거의 경우, 19세기쯤에 자전거가 단순히 앞뒤로 배치된 바퀴 둘에다 안장 달린 수레에 불과했던 시절에는 페달이나 체인뿐만 아니라 브레이크도 없었다. 땅을 발로 차서 가속하고, 제동도 발바닥으로 땅을 끌어서 했다. 굉장히 원시적이었고 신발에 무리를 많이 줬을-_-;; 것 같은데, 페달이 발명된 것과 비슷한 맥락으로 브레이크도 응당 도입되었다.

이륜차의 브레이크는 잘 알다시피 양손 핸들에 두 개가 달려 있어서 각각 앞바퀴와 뒷바퀴에 대응한다. 자전거 정도야 림(rim) 방식이라고 타이어의 금속 테 부분에다가 브레이크 패드를 압박해서 제동을 거는 간단한 방식이 많이 쓰인다. 그러나 접촉 부위가 물이나 흙먼지 등으로 오염되면 제동력이 쉽게 떨어진다는 단점도 있다.

림 브레이크는 앞바퀴에서 주로 쓰이는 듯하다. 뒷바퀴는 다른 부분이 꽉 조여지면서 제동이 걸리는데 이건 무슨 방식이라 불리는지 잘 모르겠다.
고속 주행용 고급 자전거에는 크기만 더 작을 뿐 자동차의 것과 별 차이 없는 정교한 디스크 브레이크가 달려 있기도 하나, 너무 고퀄인 브레이크는 비싸고 무엇보다도 차체를 무겁게 한다는 단점도 있다는 걸 감안할 필요가 있다. (자전거는 사람의 힘으로 움직이는 만큼, 최대한 가벼워야 한다.)

평소에 서서히 멈춰설 때에야 취향대로 쥐기 편한 쪽의 브레이크만 편파적으로 써도 된다. 하지만 급제동을 걸 때는 편파적인 제동이 위험하다. 특히 자전거 같은 가벼운 이륜차는 뒷바퀴보다도 앞바퀴 급제동이 더 위험하다. 뒤쪽이 관성을 이기지 못하고 확 들려 올라가면서 운전자를 앞으로 패대기(...)치기 때문이다.

이런 이유로 인해 자전거는 오른손 브레이크가 앞바퀴이고 왼손이 뒷바퀴이던 것이, 2010년경부터는 방향이 바뀌어 오른손이 뒷바퀴와 연결되게 되었다. 사람들이 위급한 상황에서는 왼손보다 오른손 브레이크를 반사적으로 꽉 잡는 편인데, 그걸로 앞바퀴를 붙잡으니 더 위험한 경우가 많았기 때문이다. 비슷한 시기인 2009년쯤에 보행자의 통행 방향이 오랜 좌측통행 관행을 깨고 우측으로 바뀐 것과 비슷한 맥락으로, 이륜차에도 단절적인 변화가 추가된 셈이다.

2. 자동차의 브레이크 -- 제동력 전달: 브레이크액(소형차) 방식과 공기압(대형차)

다음으로 자동차의 브레이크는 사람의 누르거나 밟는 힘으로 감당하기란 택도 안 되게 무거우면서 또 넘사벽급으로 빠르게 운동하는 기계를 신속하게 세워야 한다. 그렇기 때문에 구조가 더 복잡하다.

자동차에 가속 구동축은 일반적으로 앞바퀴나 뒷바퀴 중 한 곳에만 있다. 모든 바퀴가 구동축인 차량은 오르막과 험지 주행 성능을 매우 중요시한 군용차나 일부 SUV 정도밖에 없다. 그러나 브레이크는 어떤 자동차라도 반드시 모든 바퀴에 달려 있다. 급제동을 편파적으로만 했다간 사륜 자동차도 옆으로 홱 돌아가는 등 이륜차만큼이나 큰 위험에 빠지기 때문이다.

그런데, 자동차는 한 페달만 밟아도 이 모든 바퀴가 동등(일단은..)하게 제동이 걸리는 게 일면 신기하게 느껴지지 않는가? 이건 브레이크액(소형차의 유압-배력 방식)이나 압축 공기(대형 트럭· 버스의 에어 방식) 같은 유체의 유압을 이용해 (1) 페달 밟는 힘을 각 바퀴의 모든 브레이크에 동시에 분산해서 전하기 때문이다. 엔진의 동력을 두 바퀴에 분산 전달하는 용도로는 차동 기어 같은 톱니바퀴가 쓰이는 반면, 브레이크에서는 저런 메커니즘이 쓰인다.

그리고 차량용 브레이크에는 어떤 형태로든 '엔진의 출력'을 동원하여 (2) 사람이 페달을 밟은 힘을 증폭시켜서 더 큰 제동력이 전해지게 하는 장치가 있다. 핸들의 파워스티어링에만 증폭 장치가 있는 게 아니며, 사실은 브레이크의 증폭 장치가 더 중요하다. 유압-배력 브레이크에는 엔진 압축 행정 과정에서 생기는 진공을 이용한 브레이크 부스터가 있고, 에어 브레이크는 아예 엔진 출력을 바탕으로 동작하는 압축 공기 챔버가 따로 있다.

그러니 자동차의 브레이크는 시동이 꺼지고 나면 마치 오르간 악기처럼 진공압 또는 공기압이 남아 있는 동안만 동작한다. 그게 다 빠진 뒤에는 브레이크 페달이 아예 밟히지 않는다. 급발진 폭주가 시작됐다고 해서 무작정 시동을 꺼 버렸다면 그 뒤부터는 핸들 잠기지, 브레이크도 동작 원천이 더 보충되지 않아서 일회용 시한부 인생이 되었음을 알고 유의해야 한다. 언제든지 잡을 수 있는 자전거 브레이크 같은 걸 생각해서는 안 된다.

엔진 동력에 의존하는 브레이크 말고, 차 시동이 꺼진 뒤에 멈춰 선 차를 미끄러지지 않게 고정하는 브레이크는 주차 브레이크라고 따로 있다. 요건 보통 뒷바퀴에만 달려 있는 편인데, 주행 중에 얘를 급하게 당겨서 차를 감속하거나 세우면 역시나 편파적인 제동으로 인해 차가 돌아가 버릴 위험이 있다. 그래도 차라리 뒷바퀴를 붙잡지 앞바퀴를 붙잡는 건 더 위험한 듯하다.

3. 베이퍼 락과 페이드

자동차의 엔진은 연료의 연소와 폭발로 인해 지속적으로 열을 받으며, 이거 조절을 위해서는 라디에이터와 냉각수 같은 냉각 계통이 반드시 필요하다.
한편으로 브레이크는 제동 과정에서 자기 패드와 로터 사이의 마찰로 인해 열을 받는다. (타이어와 지면 사이의 마찰열은 또 별개의 문제) 두 손바닥만 살살 비벼도 열이 나는데, 그 무겁고 빠른 자동차를 세우는 과정에서 열이 안 날 수가 없다.

그런데 더운 날씨에 급커브 내리막에서 짧은 시간 동안 브레이크를 수십 회 이상 너무 자주 깊게 오래 밟으면 브레이크 패드가 달아오르고 과열된다. 그래서 접촉면의 마찰이 작아지고 미끌미끌해져서 "브레이크를 밟았는데 왜 서지를 못하니" 상태가 돼 버린다. 이것을 페이드(fade) 현상이라고 한다.

이보다 상태가 더 나빠지면 유압-배력식 브레이크의 경우, 브레이크액 자체가 섭씨 300도를 넘나드는 온도를 견디지 못하고 부글부글 거품이 일고 기화해 버린다. 그래서 운전자가 브레이크를 밟아도 기화된 브레이크액이 스스로 압축되어 운동량을 흡수하고, 지시가 브레이크로 가지 않는다.
브레이크 페달은 밟는 대로 쑤욱 밟혀 들어가는데, 제동은 전혀 걸리지 않게 된다! 이것을 베이퍼 락(vapor lock) 현상이라고 한다.

베이퍼 락과 페이드는 원인은 비슷하지만 성격이 다르다. 페이드는 브레이크가 정상 작동했는데도 제동력이 떨어지는 것이고, 베이퍼 락은 애초에 밟아도 제동 명령 자체가 인식되지 않는 것이다.

브레이크액은 꼭 저렇게 혹사당하지 않았더라도 시간이 흐르면서 차츰 변질되고, 수분이 섞이면서 끓는점이 점점 낮아진다(= 베이퍼 락이 더 쉽게 발생하게 됨). 그렇기 때문에 엔진 오일만치 자주는 아니어도 일정 주기로 교환이 필요하다.
냉각수는 혹한기에도 얼지 않아야 하며 브레이크액은 끓지 않아야 하니, 자동차에 들어가는 액체는 어떤 온도에서도 액체 상태가 유지되는 게 중요하다는 것을 알 수 있다.

에어 브레이크 기반인 대형 차량들은 베이퍼 락 현상이 존재하지 않는다. 디젤 엔진에 점화 플러그가 없듯, 에어 브레이크에는 브레이크액이란 게 존재하지 않는다. 에어 브레이크는 베이퍼 락 없고 제동력을 전하는 성능도 탁월하지만, 더 비싸고 큰 부품이 필요하고 압축 공기의 비축을 위해서도 엔진 출력이 상시 소모되기 때문에 천상 대형 차량용이다. (에어컨도 냉매 컴프레셔에서 전기든 엔진 출력이든 에너지 소모가 제일 많다는 점을 생각해 보자)

버스를 타 보면, 신호대기로 인해 정지했을 때 기사 아저씨가 무슨 스위치를 조작하고 차에서는 "축~ / 취익!" 이렇게 공기 빠지는 것 같은 소리가 나는 걸 볼 수 있다. (문을 여닫을 때도 비슷한 공기 빠지는 소리가 나지만, 아직 문도 열리기 전이고 멈춘 직후에)
그건 그 잠깐 서 있는 동안에도 주차 브레이크를 채우는 소리이다. 버스는 주차 브레이크도 공기압 방식이기 때문이다.

에어 브레이크를 사용하는 대형 버스· 트럭의 계기판을 보면 승용차에는 없는 '공기압' 계기가 있다. 이건 타이어의 공기압이 아니라 에어 브레이크에 비축된 공기압을 나타낸다. 주행을 하다 보면 압력이 올라가고, 엔진 회전수가 높을수록 더 빠르게 올라간다. 그 반면, 빡세게 브레이크를 자주 밟다 보면 압력이 감소하여 바늘이 왼쪽으로 돌아간다.

쉽게 말해 이건 이 차량의 제동력의 비축 상태를 나타내는 것이나 마찬가지이기 때문에 속도계· 연료계· 냉각수 온도계에 준하는 매우 크리티컬한 계기이다. 타코미터가 오른쪽 끝(지나친 고회전)에 레드존이 있다면, 공기압계는 마치 연료계처럼 왼쪽(고갈..)이 레드존이다. 굉장히 흥미로운 특성으로 보인다.

4. 자동차의 브레이크 -- 제동 방식: 디스크와 드럼

브레이크는 제동력 전달과 증폭 방식에서는 저렇게 유압-배력 방식과 에어 방식으로 나뉘고, 실제로 바퀴를 붙들어 물리적인 제동을 거는 방식에서는 디스크 방식과 드럼 방식이 나뉜다. 차축 주변에 크고 반들반들 윤기 나는 금속 원판이 보이고 타이어 휠의 비주얼도 그걸 다 노출하는 형태이면 디스크 브레이크이고, 그냥 꽹과리 내지 솥뚜껑 같은 작고 납작한 금속판만 보이면 드럼 브레이크이다. 그래서 옛날 차들과 요즘 차들은 휠의 디자인 트렌드도 차이가 난다.

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

옛날에는 대부분의 자동차들이 앞바퀴는 디스크, 뒷바퀴는 드럼 방식 브레이크를 썼다. 그러나 오늘날은 어지간한 승용차들은 100% 디스크이고, 경차 또는 반대로 트럭· 버스 같은 대형차들은 뒷바퀴 드럼을 고수하는 중이다. 드럼 방식은 디스크보다 가격 대 제동성능이 더 좋지만, 폐쇄적인 구조로 인해 과열 위험(= 페이드 현상)이 더 높다는 단점이 있다.

유독 대형차들이 언덕길에서 갑자기 브레이크가 고장 나서 사고를 내는 빈도가 더 잦은 건 (1) 근본적으로 차가 워낙 크고 무거워서, (2) 워낙 저렴하게 혹사당하는 상용차이다 보니 주행 거리가 매우 길고 과적· 차량 노후· 정비 불량 등의 위험이 있어서 외에도 (3) 드럼 브레이크라는 점도 적지 않게 작용한다. 그러니 한여름에 긴 내리막을 조심스럽게 주행할 때에는 자꾸 페달만 밟지 말고 엔진 브레이크 같은 다른 보조 제동 방법도 적극 활용해야 한다.

Posted by 사무엘

2018/04/02 08:32 2018/04/02 08:32
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1474

요즘은 좀 덜해진 감이 있지만 한때 마소에서는 자사의 운영체제인 Windows에 단순히 기술과 기능뿐만 아니라 감성을 담으려고 애쓰곤 했다. 애플 진영만 감성 마케팅을 한 게 아니라는 얘기이다.
이쪽으로 굉장히 신경을 많이 썼던 때는 크게 세 시즌으로 나뉜다. (1) 95, (2) XP, 그리고 그 다음 (3) Vista 정도 되겠다.

Windows 95는 그야말로 마소의 Windows 개발 역사상 가장 큰 격변을 이룬 작품이었다.
그러니 3.1 시절의 너무 식상했던 tada.wav를 대신하여, 참신하고 세련되고 오픈되고 모던한 이미지를 표현할 수 있게, Windows 95 부팅이 마치 미래로 가는 창문을 열어젖히기라도 한 인상을 줄 수 있는.. 그런 시작음을 외주를 줘서 개발하게 되었다.

그 유명한 "또르릉~ 띵~ 띵.." 95의 시작음을 작곡한 사람은 Brian Eno이다. 파일 이름부터가 참 거창하게 The Microsoft Sound였다.
다만, 정작 그 작곡자는 DOS고 Windows고 전혀 사용하지 않는 골수 Mac 유저였다는 것이 훗날 당사자의 회고 인터뷰를 통해 알려지기도 했다.;;

Windows 95는 누구나 듣는 시작음뿐만 아니라, 소수의 매니아만이 열어 보는 이스터 에그 화면에다가도 고유한 음악을 집어넣었다. 여기에 들어간 음악이 바로 그 유명한 Clouds이다. 이거 작곡자는 Brian Orr이니 또 다른 Brian이다. 단, 이건 길이와 용량 관계상 wav가 아니라 mid 포맷이다.

저 작곡자가 회고하기를, 작곡을 의뢰받을 때 컨셉으로 받은 키워드가 clouds, floating, peaceful이었다고 한다. Windows 95는 부팅 스플래시 화면부터가 파란 창공과 구름이었으니까..;; 그래서 그 컨셉에 맞게 멜로디를 써 넣은 결과물이 저 음악이라고 한다.
여느 음악 예제들과 마찬가지로 Windows\media 디렉터리에 있었다고는 하지만 본인은 얘는 Windows 95가 실제로 사용되던 시절에 PC에서 찾아서 들어 보지 못했다.

저거 이후로 마소의 제품에서 이스터 에그 재생 중에 그럴싸한 음악이 나온 경우는 Visual Basic 5~6의 이스터 에그가 유일했던 듯하다. 공교롭게도 저 이스터 에그도 파란 창공을 배경으로 정육면체 상자 4개가 뱅글뱅글 돌아가고 그 배경 위로 개발자 명단이 스크롤 되어 올라간다.

물론 이스터 에그라는 것도 2002년 이후로는 마소의 제품에서는 싹 자취를 감춰서 볼 수 없게 됐지만 말이다.
우리나라 지하철에다 비유하자면, 처음에 인테리어가 좀 독특하게 꾸며졌던 역들이 모두 안전을 이유로 스크린도어로 뒤덮이고 불연재 재질로 교체되어 미관이 예전보다 안 좋게 바뀐 것과 비슷해 보인다. 뭐 아무튼..

Windows NT 4라든가 98~ME 사이에서는 전자 악기 기반의 시작음들이 많이 쓰였으며 특히 chimes, chord, ding 같은 메시지 비프음도 다시 만들어졌다. 이것들은 다른 아티스트들의 작품이다.

그러다가 Windows XP는 프로그램의 시청각 요소가 완전히 쇄신했다. 이제 PC의 속도와 메모리가 충분해진 덕분에 9x 계열 커널이 수명을 다할 때가 됐고, 그리고 64비트와 멀티코어 CPU도 등장하다 보니 하드웨어가 큰 변화를 겪을 시기였다. 이 시기에 맞춰 마소에서는 OOBE (out-of-box experience)라는 말까지 만들어 내면서 새 운영체제로 '사용자에게 새롭고 특별한 경험을 선사하자'에 목숨을 걸었다. 굳이 Windows 2002 대신 XP라는 브랜드명까지 만들면서 말이다.

일단 피아노 소리 위주인 시작음, 비프음들은 다 Bill Brown이라는 작곡가가 작곡하고 오케스트라를 동원해서 연주했다. 그리고 (1) Tour를 실행했을 때 나오는 고퀄의 배경 음악들도 이 사람의 작품이다. 시퍼런 Luna 테마와 풀밭 사진뿐만 아니라 음악도 Windows XP를 뭔가 종합 예술 작품 같은 인상을 심어 주는 요인이다.

사실, Windows XP는 애초에 설치를 하다가 작업이 마무리되고 비디오/사운드 카드가 자동으로 잡히고 나면 간단한 애니메이션과 함께 (2) 몽환적인 분위기의 intro 음악이 나온다. 길이도 무려 5분 24초나 된다. 이걸 듣고서 강렬한 인상을 받은 사람이 많았을 것이다.

그런데 이 유명한 음악의 작곡자는 의외로 Bill Brown이 아니며, 정확하게 알려져 있지 않다. 인터넷 상으로는 Brian Eno가 작곡했다는 말이 많지만 저 사람은 공식적으로는 Windows 95 로고송 이후로 딱히 마소와 다시 작곡과 관련된 계약을 맺은 내역이 없다.

Susan Ciani라는 미국의 여성 작곡자를 지목하는 곳도 있으나, 이 역시 정확한 출처나 근거가 부족하다. 이 곡은 Windows XP의 정체성 그 자체로서 Tour 음악과 쌍벽을 이룬다고 해도 과언이 아닌데, 작곡자가 공식적으로 미상인 것이 무척 미심쩍게 여겨진다.

그 뒤, Windows Vista부터 도입된 "따단 따단" 그 4개 음표짜리 전자음 멜로디는 Robert Fripp이라는 사람이 작곡한 것으로 알려져 있다. 이때 이후로 마소에서는 운영체제의 음악에 큰 신경을 쓰지 않고 있다.
옛날에는 사용자가 선택한 테마에 따라 GUI의 색상과 글꼴, 각종 사운드가 싹 달라지게 하는 게 유행이었고 애초에 Windows와 Office, Visual Studio 제품들도 버전이 바뀔 때마다 프로그램 외형과 색상도 같이 바뀌던 시절이 있었거늘, 그마저도 2010년대 이후로는 약발이 다한 모양이다.

시작음처럼 운영체제나 프로그램의 구동과 함께 연주되는 음악 말고.. Windows\media 디렉터리에 예제로 제공되는 음악들도 버전별로 바뀌어 왔다.
Windows 3.1 시절에는 canyon과 passport라는 이름의 mid 파일이 있었다. 95와 그 이후까지 존속했는지는 기억이 확실치 않다.

98/2000쯤에는 '엘리제를 위하여'를 포함해 뜬금없이 클래식 음악의 미디 파일이 갑자기 쭈욱 추가되었던 걸로 본인은 기억하는데, 후대 버전에서는 몽땅 다시 사라졌다.
그 대신 ME와 XP에서는 그 당시의 최신 외국 가요 음반에서 발취한 샘플 wma 한두 곡이 잠시 들어갔다. 미디로는 town, flourish, onestop이 들어가서 오늘날 Windows 10에까지 전해져 내려오고 있다.

특히 onestop의 경우 마치 음악계의 the quick brown fox jumps over the lazy dog처럼.. 미디에 정의되어 있는 모든 악기들을 일부러 모두 동원하는 형태로 만들어졌으며, 구간별로 분위기가 오락가락 하면서 굉장히 괴랄한 흐름과 중독성을 자랑한다.
뭔가 RPG 게임의 BGM 같기도 하고.. "이 음악 들으니 문득 집 앞 편의점까지 희망찬 모험을 떠나고 싶어졌어!" 뭐 이런 말이 나올 정도라고 한다..;;

Posted by 사무엘

2018/03/31 08:34 2018/03/31 08:34
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1473

다음 버전 개발 근황 -- 글꼴

0. 들어가는 말

날개셋 한글 입력기 9.3이 나온 지 벌써 50일 가까이 지났다.
올해 초, 이걸 만들던 당시에는 정말 머리를 쥐어뜯으면서 힘든 나날을 보냈다. '조합 안에 조합 생성', '조합과 후보 자동 완성' 같은 새로운 입력 도구들을 세세한 외형부터 시작해서 이들이 내부에서 입력 엔진과 통신하는 인터페이스를 완전 무에서 처음 창조해 내야 했으니 말이다.

단순히 당장 기능이 동작만 하게 만드는 게 아니라, 앞으로 두고두고 후회가 없을 정도로 최상의 성능과 최적의 확장 가능성을 현실적으로 잘 절충하여 구현한 거라고 개인적으로 확신을 갖는 것이 매우 어렵고 힘든 일이었다.
하지만 다 만들어 버리고 나니 언제 힘든 일이 있었냐는 듯 아무렇지도 않고 세상은 그저 평온하기만 하다.

본인은 2010년대 이래로 현재, 날개셋 한글 입력기의 개발 todo list의 분량이 역대 최저인 시기를 살고 있다. 그만치 마음의 부담을 많이 덜었다.
하지만 대단원을 장식할 그 마지막 기능을 과연 어떻게 설계하고 구현할지가 만만찮은 상태이고, '저것까지만 다 만들어 놓으면 뭐 어떻게 되겠지' 그렇게 생각하던 당시와 비교했을 때 세상이나 내 상태가 그렇게 확 달라진 것 같지는 않다. 이건 당연한 귀결인 건가..;; 아무튼.. 개발 근황 소식을 전하도록 하겠다.

1. 24픽셀 글꼴 추가

날개셋 한글 입력기는 지난 9.0 버전부터 150% (144dpi) 이상의 화면 확대 배율에서 24픽셀 비트맵을 지원하기 시작했다.
이건 굉장히 뜻깊은 과업이었으나, 24픽셀은 16픽셀에 비해 글꼴이 훨씬 적고 부족하다는 게 못내 아쉬움으로 남았다. 옛날에는 이게 화면용이 아니라 도트 프린터 인쇄용 크기였기 때문이다.

그랬는데.. 이때 본인의 머리를 스친 것은 1990년대에 PC 통신을 통해 한창 굴러다니던 아래아한글용 공개 글꼴들이었다. 이런 것들은 비록 비트맵이지만 문서에다 넣고 인쇄도 할 목적으로 쓰이므로 24픽셀, 그리고 심지어 레이저용 40픽셀 글립까지 있다. 내가 이것들 생각을 왜 지금까지 못 했을까?

본인도 중학교 시절까지는 글꼴에 완전 꽂혀서 수십여 종의 공개 글꼴들을 받아서 쓴 적이 있었다. 전문 업체에서 만든 글꼴의 퀄리티에 비할 바는 못 되었지만 저마다 개성이 담겨 있었다.
이것들은 아래아한글 1.0 ~ 1.2 시절, 비트맵 글꼴 에디터가 있던 시절에 근성의 도트 노가다를 통해 만들어진 물건이었다.

2.x도 아니고 1.5쯤 되면서 아래아한글은 자체적으로 조합 로직을 정의할 수 있는 한글 글꼴 포맷까지 제정했으나, 정작 예전처럼 사용자가 고정된 조합 로직 틀에서라도 한글 글꼴을 customize할 수 있는 통로는 완전히 막아 버렸다.
그리고 1.5, 그리고 2.0까지만 해도 보급 글꼴 말고 새로운 글꼴을 구해다 쓰는 건 마치 Doom 2에서 custom WAD 맵을 얹어서 플레이 하는 것만큼이나 번거롭고 귀찮고 어려웠다.

그때까지만 해도 아래아한글은 새로운 외부 글꼴을 등록해서 쓰는 것을 고려하여 설계되지 않았으며, 심지어 글꼴 파일 내부에 자기 이름이나 제조사 같은 메타정보도 들어있지 않았었다. 2.0 전문용에서 첫 도입됐던 한양 시스템의 윤곽선 글꼴조차도 말이다. 그 파일들은 나 같은 사람이 내부 포맷 분석에도 금세 성공했을 정도로 그냥 무식한 벡터 이미지 덩어리 그 이상도 이하도 아니었다.

그 와중에 과거에 만들어졌던 싸제 한글 비트맵 글꼴을 쓸 수 없어서 현기증 난다는 사용자들의 원성이 빗발치자.. 한컴에서는 이미 만들어진 글꼴들을 아래아한글 2.x 같은 후대 버전에서 사용할 수 있게 간단한 파일 포맷 변환 유틸 정도나 만들어서 던져 줬을 뿐이었다.

이렇게 상황이 열악하다가 그나마 1993년에 출시된 아래아한글 2.1은 잘 알다시피 통합 글꼴 포맷을 최초로 도입하고 글꼴 시스템 전용 환경설정 프로그램(fontcfg)까지 도입하면서 이 바닥 시스템이 크게 개선되었다. 뭐, 과거 회상은 이 정도까지 하기로 하고..

본인은 아래아한글이 제공했던 모든 HFT 폰트 파일들을 지금도 갖고 있지만, 그 시절에 추가로 받아서 썼던 공개 글꼴들은.. 너무 옛날 것이어서 그런지 컴퓨터가 바뀌는 과정에서 소실된 듯했다. 남아 있는 게 없었다.
그래도 인터넷 각지에 있는 고전 프로그램 자료실을 뒤진 끝에.. 현재까지 날개셋에 16픽셀로만 존재하던 다음 글꼴의 24픽셀 버전을 구해서 추출하는 데 성공했다. 굽은샘물, 손글씨, 타자기, 파도.. 4종이다.

사용자 삽입 이미지

특히 '손글씨'는 16픽셀에서는 획이 거칠고 별로 보기 좋지 않은데 24픽셀이 훨씬 더 보기 좋다.
굽은샘물은 언뜻 보기에는 예쁘게 생겼지만 '게'와 '계'가 분간되지 않는 등 결함이 몇 군데 있다. 그런데 24픽셀에서도 완전히 똑같은 결함이 남아 있다는 게 아쉬운 점이다.

명조 고딕, 거기에 기껏해야 필기체 일색이던 시절보다 글꼴 부족 문제가 좀 개선됐으면 좋겠다.
뭐, 한글뿐만 아니라 영문 글꼴도 아주 부족하긴 하지만.. 이건 더 답이 없는 문제인 듯하다.

2. 글꼴들의 내부 구조 최적화

그리고, 이렇게 글꼴 관련 작업을 하는 과정에서.. 내부적으로 조합형 한글 글꼴(*.hfn) 파일을 생성할 때 사용하는 빌드 툴을 대대적으로 손질하여 다시 만들었다. 그리고 꼼꼼한 최적화 기능을 추가했다.

최적화라는 게 무슨 말인가 하면...
샘물· 타자기 같은 글꼴들은 벌수가 적고 내부 구조가 굉장히 간단하다. 하지만 8*4*4 도깨비처럼 기존의 범용적인 조합 로직에 끼워 맞춰 글꼴을 만들다 보면 결국 같은 모양의 글자를 여러 벌에서 쓰도록 복붙을 해야 하고 중복 정보가 발생하게 된다.

먼 옛날, 날개셋 한글 입력기 5.3과 함께 본인이 처음으로 작성한 hfn 생성 툴은 사용자가 작성해 준 스크립트대로 곧이곧대로만 파일을 만들었다. 하지만 다음 버전에 들어가는 hfn 파일들은 크기가 약간이나마 더 작아져 있을 것이다.

==========
Processing 샘물2.txt..
Unit count: 19/21/27
Group size: 1/2/2
Bol count: 2/1/2
Load OK! (cell size 32, trivial? 1/1/1)

Group reduced to: 1/2/1
Wrote 113 glyphs

==========
Processing 타자기.txt..
Unit count: 31/29/31
Group size: 1/2/2
Bol count: 2/1/1
Load OK! (cell size 32, trivial? 1/1/1)

Group reduced to: 1/2/1
Wrote 122 glyphs

==========
Processing 굽은샘물.txt..
Unit count: 19/21/27
Group size: 1/3/2
Bol count: 3/1/2
Load OK! (cell size 32, trivial? 1/1/1)

Group reduced to: 1/3/1
Wrote 132 glyphs


 물론 지금 제공되고 있는 샘물 계열 글꼴들은 이미 손으로 직접 최적화한 굉장히 단순한 조합 로직 기반이기 때문에 16픽셀용이 크기가 4~5KB 남짓에 불과할 정도로 작다.
그런데 수동으로 최적화하면서 지금까지 생각하지 못했던 것이 바로.. 종성 그룹을 굳이 받침이 있는 경우와 없는 경우로 분류할 필요가 없다는 것이었다. 샘물 계열은 그 정의상 애초에 그거 구분이 필요하지 않은 글꼴이니까 말이다.

바로 이런 헛점을 프로그램이 추가적으로 찾아 줬기 때문에 종성의 그룹 수가 하나 더 줄어들었다. (group size → group reduced to)

아래아한글이 옛날에 제공하던 '가는샘물'과 '필기'는 나름 자체적인 조합 로직을 갖추고 있는 파일이다. 그럼에도 불구하고 최적화 검사를 해 보니 사용하지 않는 자모 그룹, 중복되는 벌이 존재하여 파일 크기를 몇백 바이트나마 더 줄일 수 있었다(16픽셀 버전 기준). 물론 겉으로 드러나는 글자 출력 모습은 하나도 변함없고 말이다.

==========
Processing 바탕.txt..
Unit count: 31/29/31
Group size: 2/11/3
Bol count: 10/4/4
Load OK! (cell size 32, trivial? 1/0/1)

Wrote 528 glyphs

==========
Processing 바탕24.txt..
Unit count: 31/29/31
Group size: 2/10/3
Bol count: 9/4/4
Load OK! (cell size 72, trivial? 1/0/1)

Group reduced to: 2/9/3
Wrote 492 glyphs

==========
Processing 돋움옛한글24.txt..
Unit count: 124/94/139
Group size: 1/8/2
Bol count: 6/2/4
Load OK! (cell size 72, trivial? 1/1/1)

Bol reduced to: 6/2/3
Group reduced to: 1/6/2
Wrote 1349 glyphs

==========
Processing 궁서옛한글24.txt..
Unit count: 124/94/139
Group size: 1/8/2
Bol count: 6/2/4
Load OK! (cell size 72, trivial? 1/1/1)

Bol reduced to: 6/2/2
Group reduced to: 1/4/2
Wrote 1210 glyphs


2000년대 중반에 마소에서 Office Plus pack을 통해 제공했던 옛한글 글꼴은 일단 6*2*4벌 구조이다. 하지만 굴림과 바탕 말고 돋움과 궁서는 시간에 쫓겨서 대충 만들었는지 종성의 벌수가 실질적으로 더 적다. 궁서는 구조적으로 아주 정교한 글꼴인데도 종성이 두 벌로밖에 이뤄지지 않았으니 왠지 엉성해 보일 수밖에 없을 것이다. (날개셋 한글 입력기에 포함돼 있지는 않음)

아래아한글이 제공하던 24픽셀 명조도.. 중성의 벌수가 10개이던 것이 9개로 더 줄어들었다.
오히려 화면용 16픽셀 명조는 11개인데.. 더 큼직한 공간에서 더 미려하게 만들어야 할 인쇄용 글꼴이 미세하게나마 구조가 더 단순한 것을 알 수 있었다.

==========
Processing unoptimized.txt..
Unit count: 19/21/27
Group size: 2/8/2
Bol count: 10/4/3
Load OK! (cell size 72, trivial? 1/0/1)

Bol reduced to: 2/1/2
Group reduced to: 1/2/2
Wrote 113 glyphs


이건 뭐.. 최적화 기능을 구현하면서 테스트 용으로 사용했던 극단적인 예제이다.
벌과 그룹 수가 최적화 결과 얼마나 드라마틱하게 줄어드는지, 한편으로 아래아한글에서 쓰이던 24픽셀용 '타자기'체가 얼마나 비효율적인 형태로 저장돼 있었는지를 알 수 있다.

그리고.. 이미 만들어져 있는 다른 글꼴 파일을 바이너리 수준에서 변환만 할 때는 신경 쓸 필요가 없지만, 순수하게 텍스트 포맷의 스크립트로부터 조합형 한글 글꼴을 빌드할 때 해결해야 하는 문제가 하나 있다.
바로, 문자열 형태의 벌 명칭을 서로 겹치지 않고 중간 공백(slack) 낭비도 없이 최대한 조밀하게 번호로 대응시키는 알고리즘이다. 모든 벌이 한 성분(초중종 중 하나)의 모든 낱자를 사용하고 있다면 신경 쓸 필요가 없지만, 여러 벌들이 듬성듬성 부분적인 낱자 그룹을 사용할 때는 문제가 복잡해진다.

이 문제는 곧이곧대로만 푼다면 시간 복잡도가 그냥 NP 완전이 된다.. =_=;; 그런데 (1) 지도에서 여러 점들의 주변에 지명을 서로 겹치지 않고 최대한 많이 적절하게 배치하기, (2) 여러 지점들의 최단 순회 경로 구하기, (3) 컴파일러의 코드 최적화 과정에서 제한된 레지스터 공간에 구간별로 주요 지역 변수들을 적절히 등재하기, (4) 수직· 수평으로만 움직일 수 있는 여러 자동차들이 좁은 부지 안에 세워져 있고 이 차를 빼기 위해서 저 차를 빼야 되고 다른 차를 원상복구 시키는 복잡한 상황에서 특정 차를 빼내는 순서 구하기 등.. 실생활에서는 이런 부류의 intractable한 휴리스틱 문제들이 의외로 많이 존재한다.

모든 벌에 대해서 그냥 심벌 테이블을 부여하고 번호가 아니라 문자열로 벌을 식별한다면 slack 걱정을 할 필요가 없긴 하다. 하지만 겨우 날개셋이 사용하는 글꼴 파일이 그런 것까지 사용할 정도로 구조가 복잡하지는 않기 때문에 그냥 숫자 기반 인덱스 체계를 채택한 것이다. 컴퓨터에서 문자열로 아이템을 식별하는 건 포인터와 동적 메모리 등.. 단순 숫자보다 성능 비용이 더 크다.

이로써 조합형 한글 글꼴 빌드 절차는 데이터 읽기 → (글립 최적화 → 조합 로직 테이블 최적화 → 명칭 순서 최적화) → 출력의 순으로 절차가 깔끔하게 완성됐다. 컴파일하는 기능뿐만 아니라, 반대로 빌드된 hfn 파일을 다시 텍스트 기반 스크립트로 환원하는 디컴파일 기능도 이 참에 넣어서 관련 기능을 완전히 끝장을 봤다.

좋은 tool이 완성됐으니, 이제 도스 시절을 풍미했던 아래아한글용 공개 비트맵 글꼴들을 애타게 기다린다. 혹시 지금까지 갖고 계시는 분들은 본인에게 제보해 주시면 좋겠다. 이제 글꼴 분석과 빌드 툴이 완벽하게 갖춰졌고 무엇이건 내 프로그램에 반영 가능하다.

3. 한글 로마자 입력기

끝으로, 10여 년째 기능에 변화가 거의 없던 한글 로마자 입력기 빠른설정에 '공업진흥청 방식'이라는 새 템플릿이 추가되었다.
이건 macOS에서 전통적으로 지원되어 온 로마자 입력 방식인데, 정작 날개셋 한글 입력기가 제공하는 기존 템플릿 5개와는 일치하는 게 없는 독자적인 입력 방식이었다.

ㅓ, ㅡ는 표준 표기법처럼 eo, eu로 입력하지만 ㅇ은 x로 입력하고 ㅚ는 oe로만 입력하며, Shift로 쌍자음을 입력하는 게 마치 여러 입력 방식을 짬뽕한 것 같다.
공진청 방식을 실제로 즐겨 사용한다는 외국인에게서 요청을 받아서 이 기회에 템플릿을 추가했다.

이로써 로마자 입력기 중에서 쌍자음을 1타(Shift도 포함)로 입력 가능한 템플릿은 북한 방식, Korean Writer 방식, 그리고 공진청 방식 이렇게 세 종류가 존재하게 됐다.
지금까지는 ㄸ, ㅉ, ㅃ가 종성에도 들어갈 수 있게 수식이 만들어졌다. 하지만 다음 버전에서는 이를 수정하여 이 낱자들은 언제나 초성에만 입력되게 할 것이다. 로마자 입력 방식이 딱히 옛한글을 염두에 둔 입력 방식은 아니기 때문이다.

4. 나머지

(1) 홈페이지에서 날개셋 한글 입력기를 소개하는 컨텐츠를 더 추가했다.
"첫 화면"에는 한국어가 아니라 한글 차원에서 연구했다는 개발 이념을 더 강조했고, "전반적인 특징"에도 기능 소개 스크린샷을 잔뜩 추가했다.
그리고 입력 도구, 빠른설정, 텍스트 필터만을 소개하는 "입력 보조 기능 소개"라는 페이지를 새로 추가했다. 내가 지금까지 이 바닥으로 참 어지간히도 많은 기능들을 꾸역꾸역 집어넣었다는 생각이 들었다.

(2) 24픽셀 상태에서 날개셋 편집기로 일본어· 중국어 IME를 사용해 보면(빈 입력 스키마), 조합 상태를 나타내는 밑줄이 여전히 16픽셀 기준으로 찍혀서 밑줄이 아니라 취소선처럼 나타나는 버그를 뒤늦게 발견했다. 9.0 이래로 지금까지 계속 이런 버그가 있었다는 뜻인데, 이제야 발견되어서 고쳤다. 심지어 세로쓰기일 때도 이런 문제가 없는데 요건 9.0 작업 당시에 코딩 실수가 있었던 모양이다.

요건 현재까지 날개셋 한글 입력기에서 발견된 거의 유일한 버그이다. 프로그램이 죽는다거나 하는 문제도 아닌 외형적인 실수이다.

5. 맺는 말

(1) 예전에도 한번 말한 적이 있을 것이다. 본인은 사실 생각 같아서는 기능 구현뿐만 아니라 API 구조도 마음에 안 드는 것들을 다 갈아엎고 싶고, 지금의 set/ist의 파일 포맷도 다 바꿔 버리고 싶다. 저 기능들을 처음 구현하던 시절이랑, 지금 이렇게 실물이 완성된 뒤에 본인이 생각하는 날개셋 한글 입력기의 내부 구조 및 전체 그림이 서로 같지 않기 때문이다. 지금이 당연히 더 추상적이고 체계가 더 잡혀 있다.

하지만 그건 사용자의 눈에는 띄는 게 전무한 리팩터링에 불과하기 때문에, 내부 구조가 깔끔해지는 것 말고 들이는 시간과 노력 대비 단기적으로 드러나는 성과가 너무 없고 리스크도 크다.
그런 것까지 무리하게 욕심 내서 다 추진하다가는 내가 학교 졸업을 도저히 할 수 없어지니.. 그건 하더라도 졸업 후에, 날개셋 버전이 10 정도로 확실하게 넘어갔을 때의 매우 장기적인 과제로 남기고자 한다. 이미 지금도 당초 계획보다 이미 1~2년 정도 지연이 발생해 있다. 당초 계획이 없던 기능들도 이것저것 막 구현하는데 나의 귀차니즘과 슬럼프, 능력 부족까지 겹쳐서..

어쨌든, 내 근황과 신상에 큰 변화가 생기지 않은 지금 여건 하에서... 적어도 2010년대 동안은(18~19) 날개셋 한글 입력기는 잠정적으로 9.5x 정도가 마지막 버전이 될 것이다.
9.5 이후로 당분간은 새 버전이 나오더라도 사소한 기능 추가나 버그 수정 위주로만 나올 것이다. 운전에다 비유하자면, 저단에서 고rpm으로만 계속 가속하는 데 한계를 느낀다. 나도 고단으로 변속 좀 해야지..

(2) 당연하다면 당연한 얘기인데, 요즘 문자 입력기들의 추세는 확실히 언어 데이터를 기반으로 자주 사용하는 단어, 앞으로 또 나올 가능성이 높은 문구를 미리 제시해 주는 것이다.
Windows에 내장된 한국어나 중국어 IME는 15년 전이나 지금이나 동작이 크게 달라진 것이 없는 반면, 일본어 IME는 그렇지 않다. Windows XP에서는 TSF의 새로운 기능을 활용해서 조합(composition)을 만들고 있는 중에도 cursor가 조합 안팎을 자유자재로 드나들 수 있는 natural input mode라는 걸 도입했다.

그리고 Windows 8이나 10쯤에서는 전통적인 "발음 입력+space → 단어를 나눠서 구간별로 변환"이라는 동작에서 탈피하여.. 구간 구분 없이 대충 말을 입력하다 보면 다음에 입력할 걸로 예상되는 말이 같이 후보 리스트에 뜨면서 한꺼번에 뭔가 '스마트'하게 동작하는 걸로 재미있게 바뀌어 있었다.

한글과 영문은 단어 단위 조합은 모바일에서만 존재하며, PC에서는 그런 계층이 없다. 일본어는 기왕 단어와 문장이 조합창을 몽땅 거치다 보니, 거기서 할 수 있는 모든 언어적인 변환은 다 끌어들이는 것 같다.
그 반면 한글은 기본적으로 글자 단위+rule 기반의(data 기반이 아닌) 간단한 조합만 거친다. 이런 구조에서 할 수 있는 온갖 기괴한 응용 기능은 지금까지 날개셋 한글 입력기의 주된 관심사요 개발 아이템이었다.

하지만 거시적으로는 한국어의 입력도 그런 기능에다가 어절 단위의 더 큰 규모의 조합과 접목할 필요가 있다. 이를 염두에 두고 이번 9.3에서는 "조합 안에 조합 생성"이라는 입력 도구가 추가되었다. 이것은 날개셋 한글 입력기의 개발 역사상 매우 의미심장한 기능이다.
내 여건이 허락하는 한, 날개셋 한글 입력기는 한글 같은 문자를 기반으로 하여 생각할 수 있는 모든 입력 기능을 구현할 수 있고, 이를 토대로 세벌식 자판의 장점도 덤으로 부각시킬 수 있는 입력 엔진으로 굳건히 성장할 것이다. 그리고 그 결과물이 프로그램과 논문으로 더 나오게 될 것이다.

Posted by 사무엘

2018/03/28 08:33 2018/03/28 08:33
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1472

코딩을 하다 보면 한 자료형(타입)에 속하는 값 내지 개체를 다른 타입으로 변환해야 할 때가 있다. 아주 직관적이거나(C에서 정수와 enum), 작은 타입에서 큰 타입으로 가기 때문에 정보 손실 염려가 없는 상황에 대해서는 해당 언어의 문법 차원에서 대입이나 함수 인자 전달이 곧장 허용되곤 한다. 바이트 수가 대등하더라도 signed보다는 unsigned가 더 큰 타입이고, 정수보다 실수가 더 큰 타입으로 여겨진다.

그렇지 않고 정보 소실의 여지가 있거나 서로 호환되지 않는 타입에다 값을 집어넣는 건 컴파일러의 경고나 에러를 유발한다. 이 상황에 대비하여 프로그래밍 언어들은 여러 형변환 함수들을 제공하는데, 씨크하게 괄호 안에다가 타입 이름만 달랑 쓰면 형변환 연산자로 인식되는 C/C++이 여기서도 참 유별난 면모를 보이는 것 같다.

형변환이란 건 값의 초기 타입과 목적 타입이 무엇이냐에 따라 내부에서 벌어지는 일이 매우 다양한 편이다.

(a) 없음: LPARAM에서 void*, void*에서 char* 같은 무식한 형변환은 소스 코드상의 의미만 매우 과격하게 바뀔 뿐, 내부적으로 행해지는 일은 전무하다! (클래스 상속 관계를 신경쓸 필요 없는 간단한 것 한정으로)

(b) 그냥 뒷부분 짜르거나 늘리기: int와 char 사이의 변환

(c) 정수와 실수 사이를 변환: 내부적으로 일어나는 일이 분명 간단하지는 않지만, 요즘은 이런 건 CPU 명령 한 줄이면 바로 끝난다. x86 기준으로 cvtsi2sd이나 cvttsd2si 같은 인스트럭션이 있다.

(d) 고정된 오프셋 보정: 단순한 형태의 다중 상속에서 제n의 부모 클래스 포인터를 얻으려면 이런 보정이 필요하다.

(e) 함수 호출: 해당 클래스에다 사용자가 구현해 놓은 operator 함수가 호출된다. 사실, 100과 "100"처럼 숫자와 문자열 사이의 변환도 컴퓨터의 관점에서 보면 이 정도의 cost가 필요한 작업이다.

(f) 상속 계층 관계 그래프 순회: 이건 객체지향 이념 때문에 형변환 연산이 언어 차원에서 가장 복잡해지는 상황이다. 위의 1~5와는 근본적으로 차원이 다르다. 가상 상속 체계에서 부모 클래스를 찾아가거나 dynamic_cast 형변환을 하려면 자기의 타입 정보 metadata를 토대로 주변 클래스 계층 그래프를 O(n) 시간 동안 순회해야 한다(n은 상속 단계).
사용자의 코드가 아닌 컴파일러의 코드만 실행됨에도 불구하고 런타임 가변적인 반복이 발생할 수 있으며, 객체와 메모리 상태가 어떤지에 따라서 형변환 결과가 dynamic하게 달라질 수 있다!

내부적으로 벌어지는 일은 대략 저렇게 분류 가능하고, 겉으로 소스 코드의 의미 차원에서도 형변환의 성격을 몇 가지로 분류할 수 있다.
처음에 C++에는 그냥 C-style cast밖에 존재하지 않았다. 그런데 그랬더니 형변환 연산이 발생하는 부분만 검색으로 뽑아내는 게 어려웠고, 또 단순한 형변환과 좀 위험한 형변환 같은 걸 따져 보기도 어려웠다. 표현 형태가 괄호와 타입 이름이 전부이니까..

그래서 1996~97년경, C++98의 발표를 앞두고 C++에는 길고 굉장히 기괴해 보이지만 용도별로 세분화된 형변환 연산자가 4종류나 추가되었다. namespace, bool, explicit, mutable 이런 키워드들과 같은 타이밍에 도입되었다. C++이 숫자는 몽땅 machine-word int로 어영부영 때우려던 C스러운 사고방식을 탈피하고, 예전에 비해 나름 type-safety를 따지기 시작한 그 타이밍이다. (예: C와 C++에서 sizeof('a')의 값의 차이는?)

새 연산자들은 모두 *_cast로 끝난다. 옛날의 재래식 형변환은 (NEWTYPE)value라고 썼고 C++ 문법으로는 NEWTYPE(value)도 허용되는 형태였다(NEWTYPE이 딱 한 단어 토큰으로 떨어지는 경우에 한해서).
그에 비해 새 연산자들은 *_cast<NEWTYPE>(value)라고 쓰면 된다. < > 안에다가 타입 이름을 쓰는 것은 템플릿 인자 문법에서 유래되었는데 나름 직관적이고 적절한 활용 같다.

1. static_cast

얘는 일상적으로 가볍고 큰 무리 없이 일어나는 일반적인 형변환을 거의 다 커버한다. (1) 큰 타입에서 작은 타입으로(실수에서 정수, UINT에서 int, long long에서 int 등..), 그리고 (2) 범용적인 타입의 포인터에서 더 구체적인 타입의 포인터로(void*에서 타 포인터, 기반 클래스*에서 파생 클래스 포인터) 말이다. 이게 대부분이다.

그리고 형변환 operator 호출이라든가, 다중· 가상 상속으로 인한 포인터 보정도 언어에서 보장돼 있는 메커니즘이므로 알아서 처리해 준다. 정말 대부분의 상황에서 앞서 나열했던 (a)에서 (f)까지, C-style cast를 대체할 수 있는 무난한 연산자이다. 단, f에서 typeid와 RTTI까지 동원되는 제일 비싸고 난해한 기능은 없으며, 이건 나중에 설명할 dynamic_cast가 전담하는 영역이다.

2. const_cast

얘는 값이 아니라 포인터/참조자형에서 C/C++ 특유의 한정자(qualifier) 속성만을 제거해서 더 범용적인 포인터로 만들어 준다. 그러므로 용도가 아주 제한적인 형변환 연산자이다.
C++에서 공식적으로 제공되는 qualifer는 const와 volatile이 있다. 이런 한정자는 가리키는 대상 타입과는 아무 상관 없고, 포인터를 이용해 그 메모리를 접근하는 방식 차원에서 제약을 부여할 뿐이다. 전자는 읽기 전용 속성이고, 후자는 멀티스레드에 의해 값이 언제든 바뀔 수 있음을 대비하라는 최적화 힌트이다.

Visual C++에는 __unaligned라는 확장 키워드도 저것들과 동급인 한정자이다. 이 포인터는 machine word 단위의 align이 맞춰지지 않은 주소가 들어올 수도 있으니 그렇더라도 뻗지 말고 보정하라는 뜻이다(성능 오버헤드 감수하고라도). align 보정을 알아서 너무 잘 해 주고 있는 x86 계열은 전혀 해당사항이 없고, 과거에 IA64를 지원하던 시절에 필요했던 키워드이다. 이것도 포인터 한정자 속성으로서는 굉장히 적절한 예이며, 이런 속성들을 const_cast로 제거할 수 있다.

3. reinterpret_cast

이건 의미론적으로는 제일 무식하고 생뚱맞고 위험하지만 내부 처리는 제일 할 것 없는 형변환 전문이다. (1) 정수와 포인터 사이를 전환하는 것, 그리고 (2) 서로 관련이 없는 타입을 가리키는 포인터끼리 전환하는 것.. 어디 범용적인 함수나 메시지로부터 아주 polymorphic한 데이터를 전달받아서 처리할 때에나 불가피하게 쓰일 법하다.

void*를 char*로 바꾸는 건 static_*으로도 되고 reinterpret_*으로도 된다. 하지만 const char*를 char*로 바꾸는 것은 static_*나 심지어 reinterpret_*로도 안 되고 반드시 const_*로만 해야 한다.
그런데 그래 봤자 reinterpret_*과 const_*는 어떤 경우에도 실질적인 내부 처리는 (a)뿐인(= 없음).. 참 허무한 연산자이다. 실질적인 처리가 없지만 이 숫자값을 해석하는 방식을 변경하는 이유는 분야별로 여럿 존재할 수 있다는 뜻이다.

재래식 C-style cast는 따지고 보면 1~3을 그냥 싸잡아서 구분 없이 수행해 준다. 그런데 가끔 드물게 다중· 가상 상속 관계의 타입 포인터끼리 형변환을 할 때 정석대로 보정 연산을 거친 포인터를 원하는지(static_*), 아니면 이것도 아무 보정 없이 동일한 메모리 주소에서 타입만 바꿔서 해석하고 싶은지(reinterpret_*) 모호해질 때가 있다.

이런 문제도 있고, 또 C++에다가 좀 제대로 된 객체지향 언어의 기능을 뒤늦게 갖추려다 보니 새로운 형변환 메커니즘이 필요해졌다. 이쯤 되니까 형변환 연산자도 별도의 예약어로 도입해서 구분하지 않고서는 도저히 버틸 수 없는 지경이 됐다. 그럼 다음으로 제일 괴물인 형변환 연산자에 대해서 살펴보도록 하자.

4. dynamic_cast

가상 함수를 쓰면 기반 클래스의 포인터를 주더라도 자신이 실제로 속한 파생 클래스에 해당하는 멤버 함수가 알아서 호출된다.
그리고 다중 상속 때 가상 상속을 쓰면, 여러 부모 클래스들이 동일한 조부모 클래스로부터 상속받았을 때 공통 조부모가 한 번만 상속되는 마술(?)이 일어난다. 물론 객체지향 언어에서 유연한 코드 재사용성을 보장하는 모든 마술에는 그에 상응하는 성능 오버헤드가 대가로 따른다는 점은 감안할 필요가 있다.

그런데 과거의 C++은 상속과 함수 호출에서 이렇게 언어 차원의 동적 바인딩이 지원되는 것과 대조적으로, 형변환에는 "동적 바인딩 + 무결성"을 보장하는 메커니즘이 딱히 없었다. 이놈이 A의 파생 클래스이긴 하지만 더 구체적으로 A의 자식들 중에 B가 아닌 C의 파생 클래스가 진짜로 맞는지, 이 멤버에 접근하고 이 함수를 호출해도 안전하겠는지 말이다.

C++은 void*가 있을지언정, 언어 차원에서 모든 클래스들의 공통 클래스(Java의 Object 같은)라는 개념이 없다. 그리고 클래스 내부의 vbtl에 직접 접근한다거나, 가상 함수의 포인터 값을 보고 클래스 종류를 판별할 수 있을 정도로 C++이 ABI가 몽땅 왕창 노출돼 있느냐 하면 그렇지도 않다(겉에는 공통의 썽킹 함수의 주소만 노출돼 있기 때문). 뭔가 어정쩡하다.

그러니 MFC 같은 옛날 라이브러리들은 자체적으로 CRuntimeClass 같은 타입 메타정보를 구비하고, 이놈이 CObject의 파생이긴 하지만 특정 클래스의 파생형이 정말 맞는지 런타임 때 확인하는 함수를 자체적으로 구현해야 했다.
C++이 아무리 C의 저수준 고성능 제어 이념을 계승했다 해도 명색이 객체지향 언어인데 그런 기능조차 없는 건 좀 아니라 여겨졌는지, 훗날 언어 차원에서 타입 식별 정보와 전용 형변환 연산자가 도입됐다. 그 결과물이 바로 dynamic_cast이다.

함수도 virtual, 상속도 virtual인 걸 감안하면 얘의 이름은 기술적으로 virtual_cast라 해도 과언이 아닐 듯하다. 하지만 static_* 이라는 단어가 이미 있으니 그것보다 더 값비싼 형변환이라는 의미로 dynamic_*이라는 이름이 최종적으로 붙었다. static_*은 이놈이 진짜 조상 관계가 맞는지 확인하지 않고 그냥 O(1) 복잡도짜리 기계적인 오프셋 보정만 해서(필요한 경우) 파생 클래스로 형변환해 주는 반면, dynamic_*은 타입 식별자를 직접 확인까지 한다는 것이다.

가상 함수의 구현을 위해서는 함수 포인터 테이블과 테이블의 포인터(멤버)가 필요하고, 가상 상속의 구현을 위해서는 기반 클래스의 포인터(멤버)가 필요하다. 그것처럼 동적 바인딩 형변환을 구현하려면 클래스 이름과 계층 관계를 기술하는 메타데이터와 함께 그놈의 포인터(멤버)가 필요하다.

가상 함수와 가상 상속 지원을 위한 데이터는 비공개로 꽁꽁 감춰져 있는 반면, 동적 바인딩 형변환을 위한 타입 식별자 데이터는 공식적으로 스펙이 공개돼 있고 일반 프로그래머들이 언어 요소를 통해 접근할 수 있다. 일명 RTTI (run-time type info)이다.
#include <typeinfo>를 한 뒤 typeid() 연산자로 const type_info&라는 구조체, 아니 클래스를 들여다보면 된다. typeid는...

  • sizeof와 마찬가지로 오버로딩 할 수 없다.
  • sizeof와 마찬가지로 타입 이름과 일반적인 값을 모두 받을 수 있다. 단, sizeof는 값이 올 때는 괄호를 생략할 수 있는 반면, typeid는 그렇지 않아서 언제나 뒤의 피연산자를 괄호로 싸야 한다.
  • sizeof는 결과값이 무조건 정적 바인딩으로 구해지는 반면, typeid는 바인딩이 정적과 동적 사이에서 어정쩡하다. 피연산자가 타입 이름이거나, 값이더라도 int 같은 primitive type 내지 상속이고 가상 함수고 아무것도 없는 구조체라면.. sizeof와 마찬가지로 수식을 실제로 evaluate하지 않는다. 그러나 뭔가 상속 관계 규명이 필요하다 싶은 개체라면 런타임 계산이 행해진다.

쉽게 말해 typeid는 MFC로 치면 obj->GetRuntimeClass()와 RUNTIME_CLASS(classnam)의 역할을 혼자 모두 수행한다는 뜻이다.
그럼 관련 타입들에 대해 DECLARE_DYNAMIC 내지 IMPLEMENT_DYNAMIC도 어딘가에 행해져야 할 텐데, 그건 C++ 컴파일러가 typeid 연산자가 쓰인 곳을 총체적으로 따져서 알아서 처리해 준다.

이런 RTTI 기능은 대다수의 C++ 컴파일러에서 사용 여부를 옵션으로 지정할 수 있게 돼 있다.
RTTI를 사용한 상태에서 dynamic_cast를 사용하면 실제 타입이 그게 아닌데 그 파생 타입으로 형변환을 시도하는 경우.. 피연산자가 포인터였다면 NULL이 날아오고, null이 가능하지 않은 참조자를 줬다면 예외(exception)를 날리게 된다.
이것도 다중 상속까지 생각한다면 상속 관계 그래프를 타고 오프셋을 보정하는 알고리즘이 가히 판타지가 될 것 같다.

이상.
객체지향 언어라는 게 그냥 구조체에다가 this가 자동으로 전달되는 함수가 같이 딸려 있고, 상속에 다형성 정도 지원되는 게 전부라고 생각하는 게 얼마나 순진한 생각인지 알 것 같다.
PC 환경에서 C를 초월하여 C++이 보급된 게 1990년대 초쯤인데, 이 무렵에 템플릿과 다중 상속도 도입됐다. 처음부터 있었던 게 아니다. 그리고 그때부터 C++은 뭐랄까, 괴물 같은 복잡도를 자랑하는 치떨리는 언어로 변모한 것 같다.

구리고 지저분한 면모가 많지만 그래도 그 정도 객체지향 이념에다가 고성능 저수준 제어까지 이만치 잡은 건 얘가 C++이 가히 독보적인 것 같다.
그러니 형변환 연산자도 언어를 따라 이렇게 복잡해진 것이다. 일례로, Java는 final이 있을지언정 포인터도 없고 const니 volatile 같은 건 신경 쓸 필요도 없는데 뭐 저런 구분이 필요하겠는가? 그러니 지금도 여전히 C-style cast만으로도 충분한 것이다.

Posted by 사무엘

2018/03/25 08:30 2018/03/25 08:30
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1471

1. 영동과 부강 역 인근의 비밀 선로

경부선 성환 역은 동쪽 인근의 학정리 야산을 다 점유하고 있는 군부대 탄약창으로 이어지는 선로가 있는 것으로 잘 알려져 있다.
그 외에도 대전 근처의 영동 역도 서쪽으로 거대한 탄약창으로 이어지는 선로가 있다. 육군 종합 행정 학교가 영동 제일 요양 병원 근처로 이전해 오긴 했는데, 탄약창은 그것보다 더 북쪽에 있는 별개의 부대이다.

한편, 부강 역은 가까운 동북쪽으로는 철길이 아니고 도로이지만, 거대한 컨테이너 화물 기지가 있고, 또 뭔가 일반인이 범접할 수 없어 보이는 코렁시설이 있다. 단순 화물 기지이기만 했으면 저렇게 민간 지도에서 가려지고 숨겨지지는 않았을 것이다.
그리고 서쪽으로는 2010년에 '부강화물선'이 개통하여 민간 지도에도 보이는 화물 기지가 있다.

저기는 세종 자치시 중심부와 꽤 가까우며 바로 옆에 호남 고속선이 지나는 게 흥미로운 형태이다. 나름 물류 허브도 추구하는 것 같다.

2. 서울 지하철 5호선의 동쪽 지선

서울 지하철 5호선은 강동 역 이후로는 잘 알다시피 상일동과 마천 방면으로 Y 자 모양으로 노선이 갈라진다. 역 수는 마천 지선이 좀 더 많다.
상일동 지선: 고덕 차량기지가 지나는 관계로 서울 지하철 5호선 중 가장 먼저 개통한 구간이다(왕십리-상일동).
서울 지하철 2호선이 군자 차량기지를 끼고 신설동-종합운동장이 가장 먼저 개통한 것과 같은 이치이다. (그때는 성수 지선이 2호선의 본선이었음)

2010년대에 들어서 두 지선은 서로 다른 방향으로 변화하게 되었다.
마천 지선은 기존 지하철의 연장 건설로 인한 환승역이 생겼다. 오금이 3호선과 환승되고, 그리고 앞으로 올림픽공원은 9호선과 환승될 예정이다.
그 반면, 상일동 지선은 노선 자체가 하남시 쪽으로 더 연장되어 길어질 예정이다. 환승역이 생기는 것과, 노선이 더 연장되는 것 중 어느 게 더 호재일까?

상일동 지선은 서쪽이 한강으로 막혀 있어서 타 노선과 환승이 될 여지가 없는 반면, 마천 지선은 동쪽이 청량산으로 막혀 있어서 자기 자신이 더 연장될 여지가 없다. 무척 독특한 차이점이다.

상일동 쪽은 한강과 가까우며 명일 공원, 길동 공원, 고덕산 이렇게 언덕과 근린공원이 많다. 그런데 '굽은다리'라는 역은 도대체 무슨 다리가 굽었다는 말인지 모르겠으며, '고분다리'라는 명칭과도 맞물려서 초행 방문자를 더욱 헷갈리게 하고 있댄다.

마천 쪽은 둔촌동이라는 역명도 그렇고 왠지 '둔촌 이 집' 선생을 기리는 흔적이 눈에 띈다. 후손들이 자기 선조를 띄워 주려고 많이 노력을 한 것 같다. '둔촌'은 강서구의 '등촌'과는 전혀 무관한 명칭이다.

마천역은 처음 만들던 당시에는 특전사 부대와 군인 아파트 보안 때문인지 지금의 오금로· 마천로 큰길 쪽으로 출구를 못 만들고 마천 초등학교 쪽의 엉뚱한 골목길에다가 출구를 만들었다.
하지만 군부대가 몽땅 이전하고 아파트가 지어지고 있는 지금으로서는 큰길 쪽에 지하철 출구가 만들어지지 못한 게 안타까운 지경이 됐다. 사실, 지금 용산구에 있는 미군 기지가 대거 이전하고 나면.. 미군 기지 때문에 잔뜩 굴곡지고 왜곡돼 있는 기존 서울 지하철들의 선형도(특히 4호선) 눈에 더욱 띌 것이다.

3. 크게 뒤집어엎어진 서울 지하철 계획

서울에 지하철에는 원래 이렇게 계획되었다가 대판 갈아엎어져서 사라진 흑역사가 두 건 정도 존재한다.

(1)
하나는 1970년대, 양 택식 서울 시장 시절에 나왔던 구 1기 지하철 계획이다. 강남이나 여의도 따위 안중에 없이 강북 사대문 안만을 염두에 둔 방사형으로 5개 노선을 계획했다. 특히 5호선은 천호대로와 종로를 직결 운행했으며(나중에는 송파대로와 성남대로까지!!), 종로 구간은 1호선과 복복선 선로를 나란히 달릴 예정이었다.

그렇게 계획이 추진되어서 일단 서울 지하철 1호선이 갖은 난관을 뚫고 잘 개통했다. 그랬는데.. 1974년 광복절, 육 영수 여사 피격 사건이 터졌다. 그래서 양 시장 인생에서 최고의 순간이어야 했을 지하철 개통식은 아주 침통한 분위기에서 치러져야 했으며, 박 대통령도 참석을 못 했다.

생각을 해 보시라. 옛날 대한뉴스 영상을 보면 2호선 때 전대갈부터 시작해 1990년대 분당선 때(김 영삼)까지만 해도 지하철· 전철이 개통하면 대통령이 친히 와서 시승을 하고 관계자들 노고를 치하해 주는 게 관행이었다. 하물며 우리나라 최초의 지하철의 개통은 경부 고속도로의 개통에 준하는 기쁘고 뜻깊은 일이거늘, 그 당시의 기록 영상을 보면 정작 1호선 개통 때 박 대통령의 모습은 어디에서도 찾을 수 없다. 영부인이 총을 맞았으니 거기 갈 수가 없게 됐기 때문이다.

그리고 이 사건에 대한 책임을 지고 양 시장은 경질됐다. 운이 참 더럽게 없는 것 같다. 후임 구 자춘 시장은 1호선이야 이미 완공돼 버렸고 어차피 구간도 종로밖에 없으니 그렇다 치지만 나머지 1기 지하철 계획을 싹 갈아엎어 버렸다.
그는 서울을 다핵도시로 키울 생각을 하고 20분 만에 선을 쭉쭉 그어서 이례적인 지금의 2호선 순환선 디자인을 확정했다.

오늘날 서울 1기 지하철들은 초기 지하철이다 보니, 얕긴 하지만 추후 건설된 지하철들과 환승이 막장인 편이다. 1기와 2기끼리는 그렇다 치더라도 서울 지하철 최초의 환승역인 신설동 역까지 잠실 역에 준하는 평행형 승강장 막장환승인 이유는 이렇게 지하철 건설 계획의 리부트와 단절이 있었기 때문이다. 구 계획대로 1호선과 5호선의 환승을 염두에 두고 만들어 뒀던 신설동 역 지하 3층 유령 승강장이 버려지게 된 것도 같은 이유 때문이다.

(2)
다음으로 대판 나가리 난 중대 계획은.. 짐작하셨겠지만 3기 지하철 계획이다. 이건 1990년대 초중반에 계획이 나왔지만 몇 년 못 가 외환 위기· IMF· 긴축 재정으로 인해 흑역사로 전락했다.
지하철 건설 기술과 노하우가 그럭저럭 축적되다 보니, 2기 지하철들은 미래에 또 건설될 3기 지하철과의 환승을 미리 대비까지 하면서 건설되었다. 그런데 그것들이 상당수 활용되지 못하게 되었으니 안타까운 일이다.

이렇듯, 지하철 건설 역사 한 분야만 봐도 사람 일이라는 건 가까운 미래조차도 알 수 없는 것 같다. 앞에서 언급된 양 택식 서울 시장만 해도 지하철 잘 만들어 놓고는 개통식 당일에 저런 일이 터질 줄 누가 예상했겠는가?

환승 대비를 해 놓은 것으로는 7호선 논현(11호선), 6호선 녹사평(11호선), 8호선 몽촌토성(9호선, 색깔띠까지) 등 내가 당장 떠오르는 것만 해도 여럿 있다. 그나마 여의도는 십자형 환승역으로 예상이 정확하게 잘 적중했으며, 오금과 가락시장도 3호선의 남쪽 연장에 대비한 설계가 계획대로 쓰였다. 9호선이 연장되어 8호선과 만나는 건 당초 계획됐던 몽촌토성이 아니라 석촌이 당첨됐다.

3기 지하철 계획 중 기존 노선의 연장(3호선 오금, 7호선 부평구청)과 9호선 신규 건설만이 살아남았다. 이들은 2009~2012년 사이에 완공됐다. 10호선은 서울 외곽 내지 시외 구간만이 변별성을 인정받아 광역전철 신안산선으로 대체됐으며, 그야말로 2020년대 중반은 가야 결과물이 나올 듯하다.

11호선도 남쪽의 서울 외곽· 시외 구간만이 원형 그대로 살아남아서 사철 광역전철인 신분당선으로 대체됐다. 하지만 북쪽은 아직 논현까지 올라오지 못한 상태이다.
12호선은 서울 최초의 경전철로 대체되었는데, 원래 계획되었던 왕십리 환승은 가망 없고 신설동에서 시작한다.

요약하자면 구 1기 지하철은 그냥 나가리 났다. 3기 지하철은 일부만 살아남고 나머지는 일부 구간이 서울 지하철이 아니라 민자 광역전철이나 경전철이라는 생소한 형태로 부활했다.

4. 미래의 간선 철도: 경강선, 강원선, 중부내륙선

우리나라는 1970년대의 태백선 이후로 지방에 장거리 간선 철도 건설의 맥이 끊기다시피했다. 그 뒤로 생긴 철도들은 다 수도권 광역전철이나 공항 철도가 아니면 다 기존 철도의 선형을 유지한 고속화나 복선· 전철화, 선형 개량뿐이었기 때문이다.
그러다가 2010년대 중후반에 가서는 서쪽으로는 소사-원시선이 만들어지고 있으며, 동쪽으로는 철도 소외지이던 강원도에 철도다운 철도가 만들어지기 시작했다. 횡축으로는 경강선이요, 종축으로는 동해선이다.

2018년 현재 경강선은 두 파트로 나뉘어 있다. 하나는 원래 '성남여주선'이라는 이름으로 판교-이매-여주를 이으며 현재 통근형 전동차가 다니는 그 광역전철 노선이다. 다른 하나는 원주에서 분기하여 영동 고속도로와 유사한 선형을 타고, 기존 태백선보다 더 북쪽인 평창-강릉 방면으로 가는 준고속선이다.

얘는 물론 평창 동계 올림픽 때문에 만들어졌지만 올림픽이 끝난 뒤에도 나름 '동서 고속철' 역할을 잘 감당할 것이다. 영동 고속도로는 이미 2001년에 온통 고가 놓고 터널 뚫어서 지금과 같은 깔끔한 형태로 잘 개통했건만 철도가 지금까지 너무 오랫동안 낙후해 있었다.

원주 서쪽의 중앙선 철도는 이미 진작부터 복선 전철화가 완료됐으며, 선형 개량을 통해 열차의 주행 속도가 경부선 급으로 상향 조정됐다. 서울에서 강원도로 가기 위해 경유해야 하는 곳이 먼 옛날의 영주(영동선!)에서 제천(태백선)을 거쳐 원주로 점점 더 짧아졌다.

미래에, 대략 2020년대 중반쯤엔 경강선은 여주와 원주 구간이 한데 연결될 것이며, 더 나아가 판교 이후의 서쪽으로도 더 확장돼서 광명을 찍고 시흥시 월곶까지 갈 것이다. 중간에 성남, 의왕, 안양 사이 구간은 나름 외곽순환 고속도로와도 비슷한 선형이 된다는 게 아주 흥미롭다. 그래, 거기도 철도가 진작에 필요했다.
이렇게 된 이상 쭉쭉 서쪽으로 가서 제2경인 고속도로처럼 인천 공항까지 가 버려도 되지 않을까 싶다.

경강선은 그렇고.. 종축으로 동해선은 먼저 부산 시내 기장군 정도 구간이 전면적인 선형 리모델링과 동시에 광역전철로 탈바꿈했다. 서울· 수도권 광역전철이 등장한 지 무려 40여 년 만의 일이다.
그리고 과거에 동해남부선이라고 불리면서 포항 북부에서 끊겼던 철길은 계속 북상할 것이다. 그래서 영덕과 울진에 역사상 최초로 철도가 들어오게 된다. 그래서 지금 영동선의 지선으로 취급되고 있는 삼척선과 만나고, 이것까지 동해선으로 흡수되어 동해 역까지 가게 된다.

이렇게 되면 동해-강릉도 전부 동해선으로 흡수되고 영동선은 영주-동백산-동해 구간만 불리게 될 가능성도 있어 보인다.
강릉 이북으로 최북단의 제진 역 구간은 동해중부선이라는 명칭으로 불렸으니, 국도 7호선에 상응하는 길다란 종축 철도는 일관되게 동해선이 되는 게 자연스럽겠다.
이렇듯, 경강선과 동해선 모두 말단에 광역전철 구간이 있으면서 나머지 강원도 방면 구간은 찢어진 채로 공사 중이라는 공통점이 있다.

아, 까먹을 뻔 했는데... 경강선은 여주와 원주로 가는 중에 부발 역 일대에서 중부내륙선이 분기하기도 할 예정이다. 얘는 충주(충북선)와 문경(문경선)을 경유하면서 점촌· 김천(경북선)과 연결된다. 현재의 말 그대로 영남대로 내지 중부내륙 고속도로와 얼추 비슷한 선형이 되는 셈이다.

지금이야 안 그래도 좁은 땅에 이미 건설된 도로와 철도도 많다. 그러니 옛날에 경부선과 경부 고속도로를 처음 만들 때처럼 총력전 치르듯이 일을 추진할 필요는 없고, 이미 있는 구간에서 뭔가 아쉽다 싶은 missing link만 찔끔찔끔 잇는 식으로 길을 만드는 게 추세이다. 고속도로도 갈수록 세 자릿수 번호가 늘어고 있듯이 말이다.

Posted by 사무엘

2018/03/22 08:35 2018/03/22 08:35
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1470

1. 물과 공기의 차이

1기압에 온도가 20도대인 지구의 공기는 사람이 활동하기 쾌적한 환경이다. 기온이 체온에 근접하면 체열을 밖으로 제대로 내보낼 수가 없어서 더위를 느끼게 된다.
하지만 20도대의 물은 수영을 하기에 여전히 꽤 차가운 물이다. 물의 온도는 체온에 근접해야 그럭저럭 미지근하고 물놀이를 할 만하다고 여겨진다.

7~80도대, 심지어 그보다 더 뜨거운 공기는 사우나에서 겪을 수 있으며 잠깐 정도면 버틸 만하다. 그러나 같은 온도의 물은.. 닿는 즉시 화상을 입는 뜨겁고 위험한 물이다. 그렇다면 여기서 온도라는 건 도대체 과학적으로 무엇을 의미하는 걸까?
사실, 인체 내부는 온도의 변화에 의외로 취약하다. 체온이 정상보다 단 몇 도만 더 높거나 낮아지면 사람은 정상적인 활동을 못 하고 앓아눕게 된다.

저온에서는 세포의 물질대사가 정상적으로 이뤄지지 못한다. 사람이 추운 실외에서 이불 같은 거 안 덮고 그냥 자다간 그대로 동사하는 수가 있다.
그리고 반대로 고온도.. 뇌를 구성하는 단백질은 40도 정도만 돼도 생화학적으로 변성되고 맛이 가 버린다고 그런다. 여기에는 내부의 감기 같은 질병 때문에 열이 나는 것, 혹은 외부의 혹독한 무더위 때문에 열이 나는 것(열사병..)이 모두 포함된다.

특히 소아 때 이런 열병을 오랫동안 겪는 건 굉장히 치명적인지라, 병이 나은 뒤에도 머리와 몸에 영구적인 장애가 남기 십상이다. 헬렌 켈러가 대표적인 예이다. 우리나라는 한여름에 어린이집 교사와 운전사의 부주의로 인해 어떤 아이가 한여름 땡볕에 더운 차내에서 몇 시간째 방치되어 혼수 상태에 빠진 사고가 몇 건 나곤 했는데 그 애가 지금은 어찌 됐나 모르겠다.

기왕 말이 나온 김에 더 끔찍한 얘기를 꺼내자면, "왕창 고온인 공기" vs "온도 자체는 그리 높지 않지만 열전달 효율이 넘사벽급으로 높은 유체" 이 둘의 차이가 따지고 보면 화형과 팽형의 차이를 만든다. 새까맣게 탄 시체도 끔찍하지만, 검지만 않을 뿐 뻘겋게 익고 퉁퉁 불어 터진 시체도 끔찍하기는 마찬가지일 것이다.

뜨거운 공기든 뜨거운 물이든, 작열통은 의학적으로 볼 때 신체 절단과 더불어 인간이 느끼는 가장 끔찍하고 괴로운 고통으로 여겨지고 있다. 성경에서도 지옥이 괜히 결코 꺼지지 않는 "불"로 묘사되는 게 아니다. 주토피아에 나오는 것처럼 "ice them"이면 차라리 양반이지, 진짜 본좌는 "burn them"인 것이다.

수은주가 달린 일반 온도계를 펄펄 타는 불에다 던져 넣으면 재질에 따라서 불타거나 녹고 깨지고 파괴될 것이다. 그러나 펄펄 끓는 물에 넣어서 100도대의 온도를 측정하는 것 정도는 문제가 없다. 이걸 생각하면 단백질로 구성된 인체(생체)만이 그런 저고온(?)에 굉장히 취약한 재질이라는 걸 유추할 수 있다. 고온의 공기는 그나마 고온의 여파가 끼치는 '정도'가 덜한 매체이기 때문에 상대적으로 더 오래 버틸 수 있을 뿐이다.

2. 습도

앞에서 물의 온도와 공기의 온도 얘기가 나왔는데.. 사실은 사람이 공기 중에서 더위나 추위를 느끼는 것에는 공기의 온도뿐만 아니라 잘 알다시피 공기에 포함된 습기도 굉장히 큰 기여를 한다. 이런 차이 때문에 날씨가 더워도 굉장히 기분 좋게 더울 때가 있는가 하면, 그렇지 않을 때도 있다.

낮 기온이 30도를 훌쩍 넘겨 40도에 근접한다면, 직사광선은 굉장히 뜨겁고 따가우며 땀 나고 더운 게 맞다. 실내에서는 에어컨을 틀어야 한다.
그래도 기온만 높지 습도가 별로 높지 않다면 상황이 낫다. 밖에서 조금만 바람이 불거나 그늘에 들어가면 금세 시원함이 느껴진다. 그리고 저녁이 되어 해가 지면 언제 그랬냐는 듯이 기온이 굉장히 신속하게 내려간다.

이와 반대로 습도가 높으면.. 낮 기온이 30도를 채 넘지 않고 심지어 해가 안 나더라도 푹푹 찌며 쏟아지는 땀을 감당할 수 없어진다. 땀이 나도 잘 증발하지도 않기 때문에 불쾌지수가 최고로 치닫는다.
이런 날이 꼭 밤에도 기온이 내려가질 않고 열대야가 계속돼서 사람들을 고통에 시달리게 만든다. 에어컨은 온도가 아니라 습도를 낮추는 기능 때문에 더 필요하다.

습도라는 건 공기 중에 존재하는 수증기의 농도를 말한다. 물은 1기압에서 섭씨 100도에서 끓기 시작해서 몽땅 수증기로 바뀌며, 물의 끓는점이나 어는점은 잘 알다시피 공기의 압력에 따라 달라진다(고산 지대에서는 물이 더 낮은 온도에서 끓음). 물이 공기를 녹이고 있는 것만큼이나 반대로 공기도 수분을 함유할 수 있다.

그 뿐만 아니라 100도보다 낮은 온도에서도 공기와 접촉하는 수면에서는 일부가 수증기로 증발하기도 한다.
이건 안개 내지 구름과는 다른 개념이다. 그건 수증기가 아닌 미세한 물 알갱이가 공기 중을 떠다니는 것이다. 이는 마치 순수한 회색과 흑백이 교대로 촘촘하게 늘어선 디더링의 차이와도 비슷하다. 물이 어떻게 이런 두 형태로 모두 존재할 수 있는지 난 완전히 직관적으로 이해를 못 하겠다.

공기가 머금을 수 있는 습기의 한계라는 게 공기의 온도에 따라 달라지기 때문에 습도에는 절대 습도와 상대 습도라는 개념이 따로 존재한다. 물이 온도가 올라갈수록 기체를 녹이고 있기 어려워지는 것과 마찬가지로, 공기 역시 온도가 올라갈수록 습기를 품기 어려워진다. 이 때문에 같은 양의 수분을 머금고 있더라도 온도가 올라가면 상대 습도는 더 올라간다. 겨울이 전반적으로 건조하고 여름이 전반적으로 습한 것도 이런 상대 습도의 차이 때문이다.

3. 진공

그럼 물과 공기가 있는 상황이 아니라, 반대로 물과 공기가 전무하여 진공에 가까운 우주로 나가면 온도라는 게 어떤 영향을 끼칠까? 솔직히 말해 이 역시 난 잘 모르겠고 상상이 잘 안 된다.
공기 제로, 압력 제로, 습도 제로이다 보니 거기는 햇볕을 받느냐 마느냐에 따라 뻑하면 영하 1~200도와 영상 수백 도를 오르내리게 된다. 단지 그 온도의 여파가 지구 표면보다 훨씬 덜하다. 진공인 게 인체에 훨씬 더 해롭지, 온도 자체가 사람을 즉시 태워 죽이거나 얼려 죽이지는 않는다.

하지만, 그럼 우주 공간에서 온도가 영향을 전혀 안 끼치는가 하면 그것도 아니다. 그렇기 때문에 인공위성은 뱅글뱅글 돌면서 몸체가 태양열을 골고루 받게 자세를 잡는다. 이거 조절 잘못해서 배터리가 과열이라도 되면 터지는 사고가 나기 때문이다.
또한, 우주 공간에서 수성이나 금성 같은 내행성으로 날아가는 탐사선은 커다란 양산처럼 생긴 차폐막을 앞에 두르는 형태로 설계되었다.

달에 착륙했던 아폴로 우주선 승무원들 역시 직사광선을 피해서 그늘 또는 저녁 시간대를 선택해서 주로 활동했다.
그러니 이런 정황들을 종합했을 때, 진공에서의 온도라는 게 어떤 의미를 갖는지 갈피를 잘 못 잡겠다. 일단 진공이라면 앞서 언급했듯이 각종 물질의 상태가 바뀌는 온도(끓는점, 어는점??)부터가 우리의 상식을 벗어나는 형태로 바뀌어 버리기도 하니 말이다.

참고로, 사람이 우주에 맨몸으로 있으면 체내의 공기가 유출되고 체액이 끓어오르면서 신체 상태가 잠수병 이상으로 엉망진창이 되며, 수 분 이내로 의식을 잃고 곱게 질식사한다. 그렇다고 해서 눈알이 튀어나오거나 몸이 풍선 터져듯이 터지면서 끔살 당하지는 않는다. 더구나 잘 훈련받으면 수 초 정도 동안 맨몸으로 우주 공간에 노출되고도 살 수 있다.

당연한 얘기이지만 진공은 무중력과는 별개의 조건이다. 진공은 쇠구슬과 깃털이 똑같은 속도로 떨어지는 것이고, 무중력은 둘 다 둥둥 떠다니는 것이다. 물론 둘 다 현실에서는 도저히 상상이 안 되는 상황인 건 마찬가지이다만... 우주 개발 초기에 선진국에서 벌어졌던 여러 테스트· 훈련, 생체 실험-_- 중에는 진공을 버티는 것이 당연히 포함돼 있었다. 원심 가속기나 자유 낙하를 통해 흉내 냈던 무중력과는 별개의 코스이다.

4. 열이 전달되는 원리

온도를 변화시키는 열이 전파되는 메커니즘으로는 "대류, 전도, 복사"라는 세 종류가 있다. 이 개념 자체는 초· 중딩 과학 시간에 진작부터 배운다. 그런데 이게 생각보다 굉장히 심오한 개념이다. '열전달'은 전자기학, 뉴턴 역학, 양자 역학만큼이나 물리학의 엄연한 한 분야이고 공대에서 전공 필수 과목이다.

'대류'(convection)는 유체(주로 기체) 내부에서 온도의 차이가 나는 분자들이 물리적으로 직접 상하로 움직이고 돌면서 열이 골고루 전달되는 것을 말한다. 바닷가에서 바람이 끊임없이 부는 것(땅과 물의 엄청난 비열 차이!), 화재 현장에서 불꽃이라든가 뜨거운 공기가 굳이 위로 솟구치는 것이 모두 대류 현상이다.
그러니 이건 가장 거시적인 규모의 열 전달이다. 분자간의 온도 차이가 아니라 단순 농도· 밀도 차이로 인해 발생하는 '확산'과는 다른 현상이다.

열은 매체가 저렇게 몸소 움직이지 않아도 전해질 수 있다. 펄펄 끓는 냄비의 영향으로 냄비 손잡이라든가 안에 넣어 뒀던 국자까지 뜨거워지는 게 대표적인 예이다. 금속의 분자가 직접 움직일 리는 없으니, 이때는 직접 이동이 아니라 일종의 열역학적 '진동'이라는 미시 현상을 통해서.. 마치 소리가 전해지듯이 열이 전해진다. 이 현상을 '(열)전도'(thermal conduction)라고 한다.

진정 골때리는 건 가장 미시적인 현상인 '복사'(radiation)이다. 열은 전자기파의 형태로 아무 매질· 매체가 없는 곳에서도 퍼져 나가서 전해질 수 있다. 적외선이라고 다들 들어 보셨을 것이다. 애초에 전자기파는 파동 같기도 하고 입자 같기도 한 이상한 물건이니 말이다. 저 복사는 copy나 duplication과는 아무 관계 없고, '내리쬠'이라는 뜻이다.

'복사'라는 게 있기 때문에 아무것도 없는 우주 공간에서도 태양열이 지구로 전해질 수 있다. 음파(소리)는 순수한 진동일 뿐이기 때문에 공기가 없는 곳에서는 퍼져 나갈 수 없고 속도도 훨씬 더 느리지만, 복사열은 위상이 빛과 같다.
전자레인지는 그릇은 별로 데우지 않고 안의 음식만 데우는 것이 무척 기가 막히고 신기한데, 이것만 봐도 열은 대류나 전도 같은 물리적인 접촉이 아니어도 직통으로 전해지는 게 가능함을 알 수 있다. 복사는 도선의 전기 저항으로 인해 발생하는 열하고도 물론 다른 개념이다.

물을 끓이면 왜 물이 가만히 있질 않고 보글보글 사정없이 요동치는지, 무슨 근거와 원동력으로 저러는 걸까? 이건 열전달 내지 물질의 상태 변화와 관련된 여러 미시적인 현상들이 복합적으로 작용한 결과이다.
그리고 지표면에서 물과 공기뿐만 아니라 그 밑으로 땅 속에서도 물질이 끊임없이 순환하고 화산· 지진 같은 지질 현상이 발생하는 원동력도 따지고 보면 맨틀의 대류 같은 열 때문이라고 해도 과언이 아니다.

지구의 자전은 아주 서서히 느려지고 있지만, 지구 내부는 지열 때문이든 자기장 때문이든 활동이 여전히 왕성하고, 옛날보다 오히려 더 활발해지는 듯한 느낌이다. 성경이 말하는 대로 지구 발 밑에 지옥이라는 뜨거운 장소가 있다면, 지구의 내부 구조와 양상은 타 행성과는 근본적으로 다를 수밖에 없을 것이다.

5. 열병합 발전소 -- 열전달과 폐열 재활용의 실제 사례

발전소 중에는 우리에게 친숙한 수력· 화력이나 원자력 말고 '열병합'이라는 놈이 있다. 얘는 사실 화력 발전의 파생 변종이다.
물을 끓이고 증기 터빈을 돌려서 발전기를 가동하려면 열을 만들어 내야 하는데, 이 열이라는 게 열역학 이론적인 한계 내지 기술의 한계로 인해 전부 전력 생산에 쓰이지는 못한다. 거의 과반이 폐열로 버려진다. 딱히 재활용할 길이 없기 때문이다.

8~90도에 달하는 뜨거운 물이 한 트럭이 있다 해도, 그것만으로 아무리 용을 써 봤자 100도 이상으로 실제로 펄펄 끓는 물을 한 컵만치라도 만들어서 증기 기관을 굴릴 수는 없잖은가? 그런 맥락에서 말이다.

전체 열량의 합이야 물론 90도짜리 물 한 트럭이 100도짜리 물 한 컵보다 더 많을 것이다. 그러나 외부에서 에너지를 소비하여 열을 가해 주지 않는 한, 물의 온도 자체를 스스로 높이는 것은 불가능하다. 그건 열역학적으로 자연스러운 방향을 거스르는 일이기 때문이다.

열병합 발전소는 이런 어중간한 열이 담긴 온수를 수집해서 난방용으로 주변 지역에 공급해 준다. 전기만 파는 게 아니라 열도 판다. 전동차에 회생 제동이 있다면 화력 발전소에는 이런 열병합 시설이 있는 셈이다.

그럼 처음부터 모든 화력 발전소에다 열병합 시설을 추가하면 되지 않나 의문이 들 수 있다. 하지만 이 열이라는 건 폐열을 기껏 수집한다고 해도 무슨 태양 복사열처럼 간편하게 전해서 활용 가능한 게 아니다. 열이 담긴 물을 수송할 수 있는 거리에 큰 한계가 있다. 쟤들은 대류, 전도, 복사가 아니라 송유관처럼 '열배관'이라고 극한의 보온 시설이 갖춰진 비싼 특수 수도관에다가 온수를 공급하는 형태로 열을 전한다.

그러니 열병합 발전은 온수를 곧장 중앙 집중 난방용으로 활용할 수 있는 대도시 위주로 소규모 화력 발전+열병합 시설을 갖춘 '지역 난방 공사'의 형태로 운영된다.
2018년 현재 경의선 곡산 역 근처에는 전국에서 유일하게 열병합 발전소의 자체 구비가 아니라 정식 화력 발전소와(한국 동서 발전 소속) 연계하는 대규모 열병합 발전소가 있다. 전국 유일의 인서울 화력 발전소인 당인리 발전소와 비슷한 격의 명물인 듯한데, 얘들도 얼마 못 가 더 외곽으로 이전하지 싶다.

그나저나 원자력 발전소에서도 폐열이 담긴 온수(원자로 냉각용)가 나오긴 한다. 그렇다고 해서 원자로를 소형화해서 대도시 근처의 지역 난방 공사를 운용할 수는 없으니(..; ) 이런 온수는 양식 같은 다른 용도로 활용되는 편이다. 원자력 발전소는 우주 기지와 마찬가지로 육지에서 최대한 떨어진 바닷가에 건설된다는 공통점이 있으니 말이다.

6. 차든지 뜨겁든지

"나는 네가 차든지 뜨겁든지 하기를 원하노라." 이건 성경에서 예수님 말씀의 직접 인용일 정도로 유명한 문구(계 3:15)이다.
물론 성경의 저 문맥에서 제일 좁은 뜻은 양자택일하라고 해서 진짜로 '차가운 극단'으로 나가지 말고 "영이 뜨거운 가운데"(롬 12:11) 주님을 섬기라는 책망 내지 독려이다. "그럴 거면 차라리 나가 죽어!" / "학교 때려치우고 공장이나 가!" 이런 부모나 선생의 막말 꾸중이 진짜로 애더러 공장 가거나 나가 죽으라고 하는 말이 아니듯이 말이다.

하지만 뭐, 좀 더 넓게 비유적으로는 "인간이라면 모름지기 이거 아니면 저거, 모 아니면 도 진영을 확실하게 골라서 화끈하게 살아라, 박쥐 같은 밍숭맹숭 회색분자 기회주의자가 되지 마라"라는 뜻으로 볼 수도 있다.

앞서 비유를 들었던 것처럼.. 폐열만 어중간하게 담긴 미지근한 물은 아예 펄펄 끓을 정도로 뜨거운 물이나, 얼음이 껴 있을 정도로 차가운 물에 비해서 효용이 낮다. 찬물과 더운물을 섞어서 미지근한 물을 만들기는 쉽지만, 미지근한 물이 저절로 찬물+더운물로 분리되지는 않기 때문이다. 열을 가하든 냉각을 시키든 에너지를 써야 한다. 이건 물이 위에서 아래로 흐른다는 것만큼이나 절대적인 사실이다.

그러니 "차든지 뜨겁든지 하길 원한다"란, "정체되거나 뒤쳐지지 말고 늘 전진하길 바란다", "아래로 떨어지지 말고 위를 향해 오르길 바란다" 같은 말을 "열역학적 엔트로피가 감소하는 쪽으로 나아가길 바란다"라는 비유를 동원해서 한 것이라 볼 수 있다.

그 밖에..

  • 학창 시절에 열역학을 더 열심히 공부했으면, 비빔면을 끓여 먹을 때 이 정도 양은 물을 몇 번 헹궜을 때 면을 완전히 식힐 수 있을지를 숫자와 수식으로 모델링할 수 있겠다는 생각이 든다..;;
  • 물에 대해서는 "10리터를 한꺼번에 끓이는 것보다 5리터부터 먼저 데운 뒤 나머지 5리터를 추가로 부으면 10리터 전체를 더 빨리 끓게 할 수 있다.", 심지어 "뜨거운 물이 더 빨리 언다" 같은 믿기 힘든 말도 존재한다. 물에다 날씬한 돌을 잘 던지면 수면에 몇 번 통통 튀는 것도 가능한데, 그것만큼이나 본인은 저런 현상은 어떻게 과학적으로 가능한지 입증할 만한 지식이 부족하다.

  • 한국어는 '덥다'와 '뜨겁다', '춥다'와 '차갑다'의 차이가 존재하는 게 꽤 절묘한 것 같다. '덥다/춥다'는 사람이 느끼는 관점이고, '뜨겁다/차갑다'는 온도를 내는 해당 객체의 관점이다. "난 지금 덥다" / "난 뜨거운 남자다"처럼 말이다.
  • 물리라는 학문은 계속 미시적으로 파고들다 보면 결국은 역시 '파동과 입자'로 귀착된다. 그리고 직선이나 포물선이나 갖고 노는 게 아니라 결국은 삼각함수의 형태로 표현되는 진동을 논하게 된다. 중력의 영향을 받지 않는 듯한 미시세계 입자들의 끊임없는 불규칙한 운동.. 일명 '브라운 운동'은 어떻게 벌어지는지, 걔네들은 무슨 원동력으로 계속 운동하는지, 텔레비전의 백색잡음 같은 움직임도 왜 발생하는지.. 따지고 보면 참 궁금한 게 많다. 이런 것도 열역학과 전혀 무관한 게 아니다.

Posted by 사무엘

2018/03/19 08:36 2018/03/19 08:36
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1469

(2011년에 썼던 글에 내용을 보충하고, 본인의 실제 답사기를 추가했다.)

오늘날 중앙선과 동해선(구 동해남부선)의 환승역인 경주 역은 무려 3· 1 운동 직전인 1918년 가을에 생겼다. 우리나라 최초의 철도인 경인선과는 약 20년의 격차가 있지만 그래도 이것만으로도 역사가 굉장히 길다고 할 수 있다. 철도 덕후라면, 모름지기 1920년대, 30년대, 40년대 이렇게 연도만 입력하면 그 당시에 개통해 있던 철도 노선도가 머리에 쫙 떠올라야 한다.

그때 경주 역은 동해남부선 경주-포항 구간과 함께 개통한 역이었다. 중앙선은 1939년 전구간 개통이니까 그로부터 또 20년 뒤의 일이다. 다만, 동해남부선과 비슷한 시기에 경주-영천 구간도 중앙선이 아니라 경동선이라는 이름으로 경주로 가는 다른 철도가 있긴 했다. 지금 대구선의 전신뻘 된다.

중앙선이 완전 개통하기 얼마 전이던 1935년 12월, 동해남부선은 남쪽 구간이 마저 개통하여 포항-경주-울산-부산이 한데 연결되었다. 일제는 포항 이북으로도 쭉 철도를 놓으려고 하였으나 전쟁으로 인해 이 계획은 무산되었고, 그 상태 그대로 패망하게 되었다. 동해선이 그냥 동해 '남부'선으로 남게 된 게 이 때문이며, 이 철도가 일제가 한반도에 부설하던 마지막 철도였다.

본인이 전에도 글로 썼지만, 일제 강점기가 장기화됐다면 한반도의 교통 인프라도 일본의 그것과 굉장히 비슷해졌을 것이다. 자동차 도로는 좌측통행을 할 것이고 일제 강점기 때 그랬던 것처럼 한반도에도 지역별로 개성 넘치는 여러 사철이 등장했을 것이다. 동해남부선도, 경춘선도 시작은 다 사철이었다.

대륙 진출(진출이라고 적고 침략이라고 읽는다)을 염두에 두고 애초부터 표준궤로 건설되었던 경부선과는 달리, 동해남부선은 무려 762mm 협궤였다. 바로 과거의 수인선과 동일한 협궤였던 것이다. 그러나 조선 총독부가 이를 인수한 후 이내 표준궤로 개궤했다.
이렇게 완성된 경주 역 주변의 동해남부선과 중앙선의 선형은 아래와 같았다.

사용자 삽입 이미지

남서쪽의 충효동 방면을 호남선 목포 방면이라고 보고,
경주 역이 있는 동남쪽 울산 방면을 경부선 대구 방면이라고 보고,
나원 역이 있는 북쪽의 포항 방면을 경부선 서울 방면이라고 보면
이는 대전 역의 위상과 정확히 같다.

이들 철도가 처음 생긴 시절에는 초록색 선이 없었다.
그리고 경부선과 호남선이 만나는 지점도 사정이 정확하게 이와 같았다. 호남선에서 경부선 상행 방면으로 바로 가는 선로가 없었다. (곡물을 일본으로 반출하려면 부산으로만 가면 됐으니..)

그래서 목포에서 부산이 아닌 서울로 가려면 대전 역에서 기관차의 방향을 바꿔야 했으며,
영천에서 울산이 아닌 포항으로 가려면 경주 역에서 기관차의 방향을 바꿔야 했다.

이 때문에 서울을 오가는 호남· 전라선 열차들이 대전에서는 기관차의 방향을 전환하느라 정차 시간이 길었으며 대전 역이 대기 시간 동안 짬을 내어 사먹는 우동으로 유명해지기도 했다.
이런 불편을 덜기 위해 호남선은 1978년 복선화 과정에서 서울 방면으로 직통하는 삼각선이 추가되었다.

한편, 다시 중앙선 얘기로 돌아오면, 중앙선의 건설로 인해 경주에는 시내를 정면 관통하여 경주 역을 잇는 분홍색 선로가 생겼다.
그렇잖아도 중앙선 역시 남쪽에서 올라오는데, 기왕이면 금관총· 대릉원이 있는 좀더 남쪽으로 선로를 만들지 왜 저렇게 부자연스러운 급커브를 만들었는지 모르겠다.
원래 경주 역은 중앙선이 아니라 동해남부선의 선형에 맞춰진 형태라는 걸 쉽게 알 수 있다. 저것도 나름 서울-신촌 사이와 비슷한 급커브라는 생각이 든다.

본인은 초딩 시절에 흥무 초등학교를 다닌 적이 있는데,
빨강-파랑 초기 도색을 한 새마을호가 수시로 드나들던 걸 본 기억이 선하다. 벌써 20년 가까이 전의 이야기이다.
철도는 확실히 지역을 분단시키는 효과가 있긴 했다.

이 선로는 경주 시내를 정면으로, 그것도 여러 건널목을 만들면서(평면 교차) 관통한지라 문제가 많았다. 딱 큰길만 따라간 것도 아니고, 이쪽 일대의 위성 사진 지도를 보면 정확하게 수평· 수직선이 아니라 분홍색 비스듬한 선을 따라 건물들의 배치가 왜곡돼 있는 걸 알 수 있다. 그게 옛 철길의 잔재이다.

사용자 삽입 이미지

그래서 경주 인근에서 (1) 동해선 상행으로 분기의 어려움과 (2) 경주 시내 관통으로 인한 불편을 해소하기 위해 1980~90년대에 일련의 조치가 취해졌다.
먼저, (1) 1985년엔 중앙선과 동해선 상행을 연결하는 초록색 선이 새로 생겼다. 그리고 초록색 선과 분홍색 선이 분기되는 충효 제2터널 지점에 '서경주'라는 이름의 작은 신호소가 생겼다.

그 뒤.. (2) 기존의 분홍색 선로를 철거해 버리고 영천에서 경주 시내에서는 초록색과 보라색 선만으로, 즉 황성동 쪽까지 엄청난 우회를 해서 다니게 선로를 바꿨다. 분홍색 선 대신, 북쪽의 '금장터널'이 있는 곳에 아주 작은 삼각선을 만들어서 중앙선 영천 방면과 동해선 울산 방면을 왕래할 수 있게 한 것이다. 아래 그림에서 before과 after의 차이를 주목하라.

사용자 삽입 이미지

경주는 워낙 문화 유산이 많이 남아 있는 도시이다. 그러니 이런 시내 관통 선로 철거의 배후에는 유네스코의 권고가 있기도 했다고 한다. 철도와는 다른 분야로 최근엔 태릉 선수촌이 지방으로 완전히 이전했는데, 이 역시 인근에 있는 태릉과 강릉을 보존하고 유네스코 세계 유산에 정식 등재하기 위해서 취해진 조치였다. (뭐, 선수촌의 부지 크기와 확장 문제도 작용했지만 말이다.)
시대가 바뀌니 일제가 졸속으로 동해남부선 철길을 막 놓으면서 경주 시내를 땅따먹기 하던 시절과는 정반대 조치가 취해지고 있는 셈이다.

선로가 이렇게 되긴 했지만, 그래도 경주 쪽의 수요가 많기 때문에 포항-대구를 왕래하는 열차들은 어차피 경주는 들렀다 가는 관행이 한동안 계속되었다. 이 때문에 이 노선에는 전진과 후진이 비교적 자유로운 전후 대칭 동차형 열차가 다니곤 했다.

그래서 1992년 11월 1일, 북쪽에 새로 생긴 선로 분기 지점의 근처에 '금장'이라는 이름의 역이 생겼다. 개업 당시에는 일개 듣보잡 신호장에 불과하였으나, 메이저인 경주 역이 위치가 저렇게 어정쩡하던 것에 대한 반사 이익을 제대로 받아서 급성장했다.

인근에 아파트촌과 동국대 경주 캠퍼스가 있어서 위치도 나쁘지 않았다. 그래서 잠시 새마을호가 정차하는 역으로까지 발전했다. 2005년부터는 코레일이 포항 승객의 편의와 열차 속도 향상을 위해 경주 역을 무정차 통과시키고 대신 이 역에 열차를 꾸준히 늘렸다.
참고로 2005년에는 대구선이 외곽으로 이설되면서 금장과 이름도 비슷한 금강 역이 생겼으나, 이 역은 이렇다 할 인기를 얻지 못하고 이내 여객 취급 중지 처분을 받았다. 이와도 아주 대조적이지 않은지?

또한, 금장 역의 개통으로 인해 기존의 서경주 신호소는 존재의 목적을 완전히 상실하고 폐쇄됐다. 건물 자체는 철거되지 않고 경주시 부엉길 9-34라고 도로명 주소까지 할당받아 있지만, 전혀 쓰이지 않고 방치되어 있다.
이에 본인은 이번 설에 고향을 방문한 기념으로 옛 중앙선 선로의 분기 지점 주변을 답사하고 왔다.

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

중앙선의 경주 시내 관통 구선로 중에는 형산강을 건너는 교량이 있었다. 선로가 철거된 뒤에는 교각만 10년 가까이 덩그러니 방치돼 있다가 2002년경에 '장군교'라는 이름의 인도교로 리모델링 됐다. 김 유신 장군 묘가 근처에 있다고 다리 이름도 저렇게 붙었다.

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

과거 중앙선의 흔적은 교량뿐만 아니라 송화산 언덕 아래를 지나는 터널로도 남아 있다. 한때 열차가 다니던 이 터널은 이제 끝이 막힌 채 누군가의 창고로 쓰이고 있었다.

사용자 삽입 이미지

그 반면, 오늘날 새로 만들어서 쓰이고 있는 철길과 터널의 모습은 이렇다.

사용자 삽입 이미지

이 굴다리는 아주 짧고 작지만, 굴다리를 도대체 어떻게 만들었는지 다리 아래에서는 목소리가 마치 마이크를 튼 것처럼 굉장히 잘 울렸다.

사용자 삽입 이미지

근처에 있는 송화산 등산로를 약간 올랐다. 그래서 현재 쓰이는 금장 방면 중앙선 우회 선로(왼쪽)와 장군교(오른쪽)를 모두 볼 수 있는 풍경을 카메라에 담았다. 아마 본인이 지금 서 있는 곳의 아래에 아까 그 폐터널이 지나지 싶다.

송화산은 동국대 경주 캠퍼스를 감싸는 그냥 듣보잡 동네 뒷산처럼 생겼지만, 나름 국립공원이더라. 그래서 서울 북한산에서나 보던 방문객 집계 게이트도 있었다. 이 산은 경치나 문화재 같은 무슨 메리트가 있는지는 모르겠다. 

이렇게 교량과 폐터널을 둘러보고 언덕도 올라 봤는데, 그럼 서경주 신호장은 어디에 있을까?
폐터널도, 언덕도 아닌 다른 민가의 뒤쪽으로 가서 철길 근처에 접근해야 했다.
주변은 시골 마을이다 보니 개를 키우는 집이 많았는데, 이 개들이 온통 시끄럽게 짖어 대면서 외부인인 본인을 반겼다.

무슨 강력 미제 사건을 보면 "범행이 벌어지던 당시에 현장에 있던 사나운 개가 웬일로 짖지 않았다. 개를 미리 어떻게 처리했거나, 아니면 범인은 면식범이다." 이런 식으로 설명된 게 있다. (예: 2008년 대구 초등생 납치 살해 사건) 그게 무슨 의미인지를 몸소 체험할 수 있었다. 어쨌든..

사용자 삽입 이미지

우와..! 잡초로 뒤덮힌 이 폐건물을 보라. 이것이 민가나 다른 건물이 아니라 구 서경주 신호장이다. 창문이나 출입문 같은 건 일부러 다 틀어막은 듯하다. 문자로 된 그 어떤 간판이나 표지판도 존재하지 않는다.

수풀 덤불을 헤치고 현장에 도달하니, 마치 서부 전선 DMZ 안에 내팽겨쳐져 있다는 파주 장단면 사무소 폐건물을 보는 듯한 느낌이었다.
(비슷하게 DMZ 근처에 나뒹굴고 있던 녹슨 증기 기관차 정도야 인양해서 복원 후 임진각에다 전시도 해 놨다. 하지만 건물은.. 철원 노동당사처럼 해당 지역 자체를 수복하지 않은 이상, 딴 데로 옮기기가 곤란할 수밖에 없다.)

사용자 삽입 이미지

사실, 이 건물은 애초에 이 구간을 지나는 열차 안에서 차창 밖으로도 잠깐이나마 어렵지 않게 구경할 수 있다.
하지만 금장 역의 전신이라 할 수 있는 시설을 자가용을 몰고 찾아가서 이런 시간이 정지한 듯한 오지에서 대면하게 되니 참 뿌듯함이 느껴졌다. 옛 서경주 신호소를 아는 사람이라면 우리나라 철도 역사에 대한 내공이 꽤 갖춰진 철덕이라고 불리기에도 손색이 없을 것이다.

※ 추가 설명

1. 신호소와 신호장

신호소와 신호장은 모두 뭔가 철도 정거장처럼 생겼고 철도라는 그래프에서 vertex 역할을 한다. 하지만 승강장이 없고 여객 취급을 하지는 않는다.
내가 아는 바에 따르면 신호장은 단선에서 열차의 교행을 대비한다는 용도가 더 강하고, 신호소는 선로의 분기와 합류를 취급한다는 성격이 더 강하다.

철도 시설의 기술 발달과(특히 CTC화) 자동화로 인해 신호소는 더 만들지 않는 게 추세이지만, 전국에 신호소는 다섯 군데 정도 더 있다고 한다(미전, 북송정, 북영주, 용강, 신대).

2. 경주 역과 인근 역들의 미래 운명

한때는 경주 역에서 합체· 분리를 하는 포항· 울산 행 새마을호 복합 열차가 다녔고 서울-부전 새마을호까지 경주 역을 경유하였으나, 2010년에 KTX 신경주 역이 개통한 뒤엔 다 이제 옛날 추억이 됐다. 지금은 경주에서 서울로 바로 가는 열차는 레어템인 중앙선 열차(밤차 또는 낮의 완행)뿐이다. 그러니 서울로 가려면 동대구 역에서 열차를 갈아타든가 아니면 신경주 역으로 가야 된다.
신경주 역에서 서울로 가는 KTX가 평균 4~50분 간격으로 신경주 역에 정차해 주고 있으니, 이 구닥다리 역에 장거리 열차를 남겨 둘 이유가 전혀 없는 것이다.

포항은 한때는 KTX 비수혜 지역으로 여겨져서 서울-포항 새마을호가 하루 2차례 다니긴 했다(경주 대신 서경주에 정차). 그러나 이 역시 2015년에 동해선 KTX가 개통하면서 폐지됐다.
앞으로 몇 년 안 가 지금 경주 시내의 재래선 철길들은 다 없어질 예정이다. 기존 중앙선과 동해남부선조차도 신경주 중심으로 복선 전철화· 선형 개량을 거듭할 것이기 때문이다.

단, 신경주 뿐만 아니라 현곡 초등학교 근처에도 지금의 서경주와 나원 역을 대체하는 역이 생길 예정이니 이는 반가운 일이다. 다만, 난립하고 있는 여러 역명들의 교통 정리가 필요해 보인다.
그리고 경주 역은 역사적 상징성을 인정받아, 철길이 없어지는 것과는 별개로 건물 자체는 영구 보존하기로 지난 2013년경에 결정되었다. 그럼 이웃의 다른 지역은 상황이 어떨까?

  • 영천: 역시 경주와 비슷한 시기에 생겼고 중앙선과 대구선의 환승역이지만, 고속철의 영향을 받은 것이 전혀 없고 주변의 지역이 바뀌는 것도 없다 보니.. 지금의 위상이 계속 유지된다. 그냥 근처의 동대구 역에 빌붙는 게 더 편하니까.
  • 포항: 원래 있던 역은 보다시피 싹 없어지고 사라졌다.
  • 울산: 고속선과 기존 동해남부선이 서로 너무 멀리 떨어져 있는 덕분에 고속철 울산 역과 기존 태화강 역이 공존하게 된 경우라 하겠다.

Posted by 사무엘

2018/03/16 08:30 2018/03/16 08:30
, , ,
Response
No Trackback , a comment
RSS :
http://moogi.new21.org/tc/rss/response/1468

1. Java 언어가 쓰이는 곳

Java는 C++과 달리 로컬 환경용으로는 그다지 재미를 못 본 언어 및 런타임 환경이다.
콘솔(게임기 말고, 명령 프롬프트..)용 프로그램이 Java로 만들어진 건 거의 못 봤다. 오히려 Java는 한때는 표준 입력으로부터 숫자 한 줄 입력받는 것조차도 온갖 패키지를 import하고 예외 처리 try catch까지 갖춘 뒤에야 가능한 불편한 언어였다.

GUI(프레임워크 이름이 Swing이던가?)로 넘어오면 VirtualBox나 OpenOffice처럼 일부 크로스 플랫폼 프로그램이 GUI 껍데기를 Java로 만든 경우가 좀 있다. (Windows 한정으로는 C#의 Windows Form와 경쟁?) 아, 직장에서 일정 관리 용도로 사용하는 ProjectLibre도 흔치 않은 Java 기반 로컬 GUI 프로그램이다.
하지만 Java가 제공하는 GUI는 외형이 네이티브 GUI에 비해 이질적이고 느리고 런타임 오버헤드가 커서 범용성 말고는 가성비가 좋지 않았다.

한편, Java는 애플릿(Applet)이라는 이름으로 웹(클라이언트)에서 돌아간 적도 있다. 웹에서 꽤 고차원적인 수학 그래픽, 화면 왜곡과 전환 애니메이션, 시뮬레이션(특히 교육용) 등을 출력할 목적으로 플래시와 경쟁하는 구도로 한때 쓰였으나.. 그것도 다 지나간 일이다. 현재는 망했으며, 개발사로부터 지원도 끊긴 지 오래다.

오늘날 Java는 로컬 PC가 아닌 안드로이드 앱, 그리고 jsp 기반 서버사이드 언어(웹 서버)로 회생해 있다.
뭐, Java 런타임을 컴퓨터에 설치해 보면 설치 중에 '전세계 수십억 개의 기기가 Java를 기반으로 돌아가고 있습니다'라고 자랑하는 문구가 뜨기도 하는데, 그것도 임베디드보다는 모바일을 말하는 게 아닌가 싶다.

Java는 오늘날 그렇게 됐고 로컬 PC 환경에서는 지금도 수많은 프로그래밍 언어들이 난립해 있지만, 웹에서는 그야말로 Java에서 이름만 빌려온 JavaScript로 대동단결 천하통일이 이뤄진 게 신기하기 그지없다.

2. 새로운 언어

애플에서 Objective-C에 한계를 느끼고 Swift라는 언어를 만들었더니,
그에 질세라 안드로이드 진영에서도 Java 대신 '코틀린'이라는 완전히 다른 언어를 만들었다. 왕년에 C++ 컴파일러를 열심히 만들었던 사람이 D 언어를 개발했듯, Java 기반 안드로이드 개발 환경을 열나게 만들었던 JetBrains라는 회사에서 전용 언어도 만들고 이를 Google에서도 채택한 것이다.

오늘날 베이직은 마소에서밖에 만들지 않는 언어가 됐고, 파스칼은 그냥 델파이의 전유물이 됐고 이제는 델파이라는 이름 자체가 RAD 툴 겸 프로그래밍 언어의 이름으로 등극했다. 언어가 워낙 많이 마개조됐기 때문이다. 또한 옵씨의 경우는 애초부터 애플이 언어에 대한 일체의 권리를 언어 고안자로부터 사 버려서 사유화했다.
저런 언어들에 비해, C/C++은 너무 심하게 파편화가 됐을지언정--언어 문법 자체보다는 라이브러리나 ABI 계층에서--, 특정 기업에 의해 좌지우지된다는 느낌은 상대적으로 덜 든다.

Visual Studio 등 요즘 IDE들은 프로젝트 전체에 존재하는 클래스들을 쭉 보여주는 기능이야 당연히 기본으로 갖추고 있다. 그런데 클래스들을 namespace 계층 + 이름의 알파벳 순으로만 보여주는 게 아니라, 기반 클래스별로 분류해서 보여주는 기능이 있으면 프로젝트들의 성격을 파악하는 데 더 도움이 될 것 같다. 그러면 그 클래스들의 성격을 파악할 수 있으니 말이다.

3. 간단한 자료형과 복잡한 자료형 or 클래스 객체

오늘날 객체지향을 표방한다는 많은 고급 언어들이 int 같은 (1) primitive type과 (2) 클래스 객체, 혹은 (1) 스칼라와 (2) 복합 자료형(리스트 같은)을 서로 구분해서 다루고 서로 다르게 취급한다. 함수 인자와 리턴값을 주고받을 때 (1)은 값을 그대로 전달하고 (2)는 메모리에 한 인스턴스만 둔 뒤 주소값만 주고받고 레퍼런스 카운팅을 하는 것이 대표적인 차이점 되겠다. Java, 파이썬 등 여러 언어들이 이런 정책을 사용한다.

순수 극한 객체지향 언어 중에는 1과 2의 구분조차 없애고 모든 것을 객체로 취급하여 타입 식별자라든가 기반 클래스 소속을 부여하는 물건도 있다. 하지만 그렇게까지 하기에는 속도와 메모리 오버헤드가 너무 크고 실용성도 떨어지니 많은 언어들이 최소한의 primitive type 정도는 허용하는 타협을 한다.

C++이야 어느 타입이건 어느 방식으로 전달할지(값, 주소/참조)를 몽땅 명시적으로 수동 지정이 가능하다. 그러나 포인터를 노출하지 않는 언어에서는 그런 구분이 프로그래머의 지정 없이 자동으로 행해진다. 포인터가 없는 언어라고 해서 포인터가 원래 하던 일 자체를 안 하는 것은 전혀 아니니까 말이다.

그런데 1과 2의 얼추 중간쯤에 속하는 물건은 문자열, 그리고 단순 구조체 정도다.
문자열이야 언어 차원에서 상수 리터럴도 존재하고 정말 기본 자료형과 복합 자료형의 중간에 속하는 독특한 물건인지라, 각 언어와 라이브러리마다 구현 형태가 제각각이다.

그리고 생성자, 소멸자, 상속, 가상 함수 따위 전혀 없고 레알 int 같은 primitive type의 묶음으로만 이뤄진 레알 C 스타일 구조체를 프로그래밍 용어로는 POD(plain old data)라고 한다. C++의 경우 POD 구조체만이 중괄호 { }를 이용한 멤버 별 값 초기화가 가능하다.
물론 POD도 개당 수십~수백 바이트를 차지하는 덩치 큰 놈이 될 수도 있지만 이는 논외로 하고..

단순 구조체를 클래스와 구분시킨 것은 C#의 신의 한수로 보인다. 사실, POINT, SIZE, COMPLEX(복소수)처럼 숫자 둘로만 달랑 이뤄진 간단한 구조체는 상속이 뭐고 없고 함수 인자도 그냥 값 형태로 전달하고 싶은 그런 물건들이니 말이다.

4. sizeof 연산자가 없음

개인적으로 Java를 쓰면서 C++에 비해 굉장히 특이하다고 오래 전부터 생각했던 점은..
가장 먼저, (1) int를 함수에다 주소/참조로 전달을 할 수 없어서 swap 함수를 구현할 수 없다는 것이다. int는 무조건 값으로만 전달되니 말이다.

(2) 클래스에 소멸자라는 게 없다 보니, 메모리는 GC 덕분에 뒷일 생각할 필요 없이 new만 늘어놔도 되는데 파일은 닫는 코드를 수동으로 매번 써 줘야 하는 게 처음엔 아주 웃기게 느껴졌었다.

(3) 그리고 끝으로.. sizeof 연산자가 없는 것에서 한번 더 경악했다. 수동 메모리 할당이 없고 포인터도 없고, sizeof마저 없다는 건 어떤 개체의 메모리 내부 덤프 같은 건 꿈에도 생각하지 말라는 얘기다.
primitive type이야 개별 크기가 어떤 기기의 JVM에서도 불변 동일하니(가령, int 4바이트, long 8바이트..) 굳이 sizeof에다 요청하지 않아도 되고..

하긴, 특정 개체의 메모리 주소 같은 걸 어디에다 낼름 누설해 줄수록 프로그램의 엔트로피가 커지고 Garbage collector가 추적해야 하는 영역이 넓어지고, 메모리 누수와 잘못된 포인터 에러가 날 확률이 높아지니.. 그런 건 최대한 애초에 할 필요가 없게 만들어야 할 것이다.
하지만 바이너리 덤프를 바로 못 하면 파일을 읽고 쓰는 작업도 좀 불편할 것 같다. 하다못해 과거에 베이직조차도 포인터는 없어도 숫자의 binary dump를 문자열 형태로 얻거나 그걸 디코딩하는 함수는 있었거늘 말이다.

C#은 Java처럼 가상 머신 기반에 자동 메모리 관리가 제공되는 언어이지만 이런 것들이 Java보다는 융통성이 있다. ref라는 키워드가 있어서 primitive type도 call by reference가 가능하다.
그리고 sizeof 연산자가 제한적으로 지원된다. primitive type과 단순 구조체 한정으로만 사용 가능하며, 자동 관리를 받는 자기 객체(managed class)에 대해서는 sizeof를 여전히 할 수 없다.

C#의 초창기 구버전에서는 아예 unsafe 코드 안에서만 sizeof를 사용할 수 있었지만 나중에 제약이 완화되었다.
그래도 C#과 Java 어느 경우든, sizeof라는 건 저수준 메모리 접근과 관계가 있는 기능이지, 가상 머신 고수준 코드와는 어울리지 않는 건 공통인 듯하다.

5. 객체의 배열

그러고 보니 Java는 클래스 객체들이 다 기본적으로 포인터 단위로 취급된다는 특성상, 객체의 동적 배열을 만드는 것도 좀 불편하다.

MyObject[] arr = new MyObject[n];

이건 MyObject들을 담을 배열 객체부터 하나 만드는 것이다. 그 뒤에 arr[0]부터 arr[n-1]에다가 MyObject의 인스턴스를 new로 할당하는 건 사용자가 또 직접 해야 한다.
C++이야 Java처럼 행동하고 싶으면 MyObject **arr을 하면 되고, 아니면 MyObject가 default 생성자만 있다면 곧장 MyObject *arr = MyObject[n]으로 객체의 배열을 만들 수 있으니 융통성이 있다.

그리고 한 객체가 여러 클래스들을 돌아다니면서 쓰이다 보면, 이 오브젝트가 값만 일치하는 게 아니라 본질적으로 그 오브젝트가 맞는지.. C++로 치면 주소값이 같은지, Java조차도 문자열은 equals 대신 ==를 써서 행하는 그 비교 대상값이 일치하는지.. 주소를 직접 확인하고 싶은 경우가 있다.

C/C++은 & 연산자가 있으니 일도 아닌 반면, Java는 디버거 창이 아닌 로그 확인을 위해서는 toString을 일일이 해 줘야 하는 것이 불편한 점으로 남는다.
포인터라는 게 위험하다고 직접 노출을 금기시하다 보니, 포인터로 직통으로 할 수 있는 일까지 좀 불편하게 바뀌는 건 어쩔 수 없나 보다.

6. 클로저

C++은 수동 메모리 관리뿐만 아니라 pointer-to-member(더 나아가 함수 포인터라는 것 자체까지)라는 것도 오늘날의 타 언어들이 제공하는 깔끔한 클로저와는 전혀 관계 없는 원시적이고 지저분한 물건이다. C/C++은(정확히는 C가) machine word를 정말 좋아하는 언어이며, '포인터' 하나만으로 간편하게 구현 가능하지 않은 요소는 쿨하게 제공 안 하는 게 전통적인 설계 철학이었다.

그러니 함수 안에 함수를 만드는 걸 지원하지 않으며(당대의 경쟁 언어이던 파스칼과 달리), C++도 클래스 안에 클래스, 함수 안에 지역 클래스 같은 건 전적으로 접근성 scope 구분만 할 뿐, 자기 밖에 있는 클래스 멤버나 함수 지역변수에 자동으로 접근하는 메커니즘 같은 건 제공하지 않는다. 즉, Java 용어로 말하자면 static class만 지원한다는 것이다.

C++만 쓰다가 Java나 Objective-C 같은 타 언어에서 this 내지 상부 클래스 멤버에 접근 가능한 함수를 스레드 콜백 등으로 자유자재로 넘겨줄 수 있는 걸 보니 아주 신기했다. 요즘은 함수형 언어 영향을 받아서 함수 몸체를 이름조차 안 붙이고 바로 넘겨줘도 되니 더 편하다.

이것도 타 언어들이 더 객체지향 철학에 따른 것이고, C++이 기괴하고 경직된 구조의 언어인 셈이다. 물론, C++의 사고방식은 저런 유연한(?) 함수 포인터(C++ 용어), 셀렉터(옵C 용어), 클로저(???)를 구현하기 위해 내부적으로 부과되는 시공간 성능 오버헤드가 무엇인지 생각하는 데는 도움이 될 듯하다.

C++은 저게 없는 대신에 P2M을 갖고 있는 셈인데.. C++의 또 다른 괴물 기능인 다중 상속과 연계하려다 보니 P2M도 도저히 '날포인터' 하나만으로 간편하게 구현할 수가 없어졌으니 참 아이러니이다. 이건 언어 설계 차원에서의 결함이나 마찬가지라고 봐도 할 말 없을 정도이며, 이와 관련하여 본인이 몇 년 전에 글을 쓴 적이 있다.

그나저나 Java의 상속 "extends A"는 C++로 치면 ": public A", 다시 말해 언제나 public 상속과 같은 것이겠지?
난 부모 멤버들에 대한 접근에 더 많은 제약을 가하는 private, protected 상속은 사용해 본 적이 없다.

7. 자동 메모리 관리, 동적 배열 등, 나머지 생각들

뭐, 직장에서 Java 개발도 좀 해 보니 깔끔한 1파일 1클래스 구조에다 헤더와 소스 구분이 없고 코드 파싱과 빌드가 정말 광속인 것(C++ 외의 타 언어들이 대부분 그렇지만), throw IllegalArgumentException("value must be >=0") 예외 처리가 사실상 assertion failure이나 마찬가지이니 assert(0 && "error") 이런 테크닉이 없어도 되는 것들은.. 마음에 든다.

ABI 계층이 파편화 없이 딱 잘 통합돼 있고, 무식한 헤더 파일 대신 패키지로부터 추출· 복원된 프레임워크 소스와 코딩 컨벤션.. 매번 다시 컴파일 되면서 특정 타입과 완전히 결합해 버리는 C++의 템플릿 대신에, 진짜로 유연한 void*를 캡슐화했다고 볼 수 있는 제네릭.. 이런 건 부럽기도 하고 현대의 프로그래밍 언어와 프로그래밍 환경이 얼마나 발전했는지를 뒷북으로나마 느낀다.

프로그래밍에서 "네이티브 코드 + 메모리 100% 수동 관리"(C/C++) 아니면 "가상 머신 + garbage collector 기반의 메모리 자동 관리"(C#/Java)의 차이는, 자동차 운전으로 치면 수동 vs 자동 변속기와도 비슷할 정도로 큰 차이인 것 같다. 자동차에서는 면허 조건이 달라질 정도로 큰 차이를 만들며, 프로그래밍에서도 뒷일 생각 안 하고 마음대로 new를 남발해도 되냐 그렇지 않느냐의 차이는 매우 크다.

(그럼 메모리가 자동 관리되는 언어에서는... 무슨 서버나 GUI 프로그램이 아니고 일체의 아이들 타임이 없이, 자기 할 일만 일괄 처리하고 끝나는 콘솔(명령 프롬프트)+단일 스레드 프로그램이라면 GC가 언제 어떻게 개입하여 동작하는지 의문이 든다. 뭐 그냥 메모리 할당 부분에서.. 자원 반납 없이 지금까지 메모리를 사용한 양이 도를 넘어선다 싶으면 그때 동작할 수도 있긴 하겠다.)

C++을 까는 사람들의 심정은 이해한다. 하지만 C++이 그렇게 지저분하고 자비심이 없는 대신에 어떤 넘사벽급의 강력한 네이티브 코드를 생산할 수 있는지, 그리고 Java가 편한 대신에 내부적으로 성능을 얼마나 많이 희생했고 런타임 오버헤드가 더해졌는지를 전부 논하지 않고 단편적인 비교만으로 언어 호불호를 논하는 것은 바람직한 태도가 아니라고 여겨진다. 둘 다 장단점이 있고 고유한 주 용도가 있는 법이다.

옛날에 잠깐 써 봤던 파스칼은 포인터도 있고 자유로운 call by reference도 지원했지만 그 포인터가 C처럼 막강하고 배열과 연계되는 건 절대 아니며, 동적 배열을 못 만들었다. 아무리 파스칼이 교육용 언어를 표방하고 만들어졌다 해도 베이직으로도 가능한 기능이 없는 건 말이 안 되니 저건 후대의 파생 언어에서 개선되었지 싶다.

Posted by 사무엘

2018/03/13 08:34 2018/03/13 08:34
, ,
Response
No Trackback , 4 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1467

Windows API에서 BitBlt는 DC간에 비트맵 블록을 찍어 주는 아주 중요한 함수이다.
장치 독립 비트맵인 DIB라는 게 컬러 비트맵의 원활한 처리를 위해서 Windows 3.0에서 처음 도입되었지, DDB와 관련된 CreateBitmap, BitBlt 같은 함수, 그리고 컬러 brush 자체는 Windows의 초창기부터 있었다.
단순히 memcpy나 memmove 같은 함수와는 달리, BitBlt는 1차원이 아니라 2차원 평면을 표현하는 메모리 영역을 취급하는 관계로 동작 방식이 더 복잡하다.

BitBlt의 처리 대상인 두 DC는 내부 픽셀 포맷 같은 게 당연히 서로 호환이 돼야 한다.
원시적인 모노크롬 비트맵의 경우, 위치와 크기에 해당하는 좌표의 x축이 바이트 경계(8의 배수)로 딱 떨어지지 않을 때의 복잡한 보정이 필요하다.
그리고 원본과 타겟 DC가 동일한 경우, memmove 같은 overlap 처리도 x축과 y축 모두 고려하여 memmove보다 더 복잡한 상황 가짓수를 처리해야 한다.

BitBlt는 비트맵을 그냥 찍는 게 아니라 원본(S), 타겟(D)에 대해서 비트 단위 연산을 시킨 결과를 집어넣도록 아주 범용적으로 설계돼 있다. 일명 raster operation이다.
게다가 래스터 연산의 피연산자가 저 둘만 있는 게 아니라 타겟 DC에 지정되어 있는 브러시 패턴(P)까지.. 무려 세 개나 존재한다. 그래서 BitBlt는 PatBlt라든가 InvertRect 함수가 하는 일을 다 할 수 있을 정도로 범용적이다.

원본 S를 있는 그대로 복사해 넣는 건 SRCCOPY이고, 그냥 타겟 비트맵을 반전만 시키는 건 ~D이다.
그리고 마스크 비트맵(흰 배경에 검은 실루엣) M과 그림 비트맵(검은 배경에 실제 그림) S에 대해서 D&M|S (각각 and, or 연산)를 해 주면 보다시피 직사각형 모양이 아닌 스프라이트를 찍을 수도 있다. 래스터 연산을 갖고 할 수 있는 일이 이렇게 다양하다.

BitBlt가 사용하는 래스터 연산은 3비트짜리 정보(S, D, P)에 대해서 임의의 1비트(0 또는 1) 값을 되돌리는 함수라고 볼 수 있다. 이 함수가 받을 수 있는 인자의 종류는 8가지(2^3)이고.. 서로 다른 래스터 연산 함수는 2^(2^3)인 총 256가지가 존재할 수 있다.
그리고 SRCCOPY, SRCPAINT 같은 것들은 그렇게 존재 가능한 래스터 연산 함수를 나타내는 값이다. 각 변수별로 S는 11110000, D는 11001100, P는 10101010 이런 식으로 정해 놓으면 00000000부터 11111111까지가 S|D, D&~P 등 각 변수들을 조작한 모든 가짓수를 나타내게 된다.

그런데 컴퓨터에서 범용성과 성능은 대체로 동전의 양면과도 같아서 하나를 살리다 보면 다른 하나를 희생해야 하는 관계이다.
the old new thing 블로그의 설명에 따르면.. 과거 16비트 시절에 BitBlt는 사용자의 요청을 파악해서 좌표 보정 같은 전처리 준비 작업을 한 뒤, 실제로 for문을 돌면서 점을 찍는 부분은 내부 템플릿으로부터 기계어 코드를 실시간으로 생성해서 돌렸다고 한다. 이게 무슨 말인가 하면.. 단순히

void Loop(int l, int t, int r, int b);
Loop(r.left, r.top, r.right, r.bottom);

수준이 아니라

template<int LEFT, int TOP, int RIGHT, int BOTTOM>
void Loop()
{
    for(int j=TOP; j<BOTTOM; j++)
        for(int i=LEFT; i<RIGHT; i++)
            어쩌구저쩌구;
}

Loop<r.left, r.top, r.right, r.bottom>();

이런 걸 추구했다는 뜻이다.
비트맵을 찍을 때 범위 체크는 매 픽셀마다 그야말로 엄청나게 자주 행해지는 일이다. 그러므로 그 한계값을 컴퓨터의 입장에서 변수가 아닌 상수로 바꿔 버리면 레지스터도 아끼고 성능 향상에 도움이 될 수 있다.

16비트 Windows에는 32비트 OS 같은 가상 메모리 관리자라는 게 없으며, Java/.NET 같은 가상 머신과 garbage collector도 없었다. 그 대신 (1) 메모리의 단편화를 방지하기 위해 moveable한 메모리 블록들의 주소를 수동으로 한데 옮기고 (2) discardable한 메모리 블록을 해제하는 동작이 있었다.

가상 머신이 없으니 just-in-time 컴파일이라는 개념도 있을 리 없다. 하지만 BitBlt의 저런 동작은 Java 내지 JavaScript의 JIT 같아 보이기도 한다. 물론 진짜 JIT 기술보다는 코드 생성 패턴이 훨씬 더 정향화돼 있고 단순하지만 말이다. (뭐, BitBlt의 세부 알고리즘 자체가 단순하다는 뜻은 아님)
그리고 그 시절엔 DEP도 없었다. 메모리에 데이터가 담겼건 실행 가능한 코드가 담겼건, 아무런 차별이 없었다.

게다가.. 저 때는 그래픽 출력과 관련된 하드웨어 지원조차도 없었다. 1990년대 일반 VGA 화면에서는 화면이 갱신될 때 마우스 포인터의 잔상이 남지 않게 하는 처리조차도 소프트웨어적으로 해야 했다. IBM 호환 PC는 전통적으로 게임기용 CPU에 비해서 멀티미디어 친화적이지 않은 컴퓨터로 정평이 나 있었으며, 그나마 좀 미려한 그래픽 애니메이션을 보려면 한 프로그램이 하드웨어 자원을 독점하는 도스밖에 답이 없었다. 그러니 BitBlt 같은 함수는 CPU 클럭을 하나라도 줄이려면 정말 저런 눈물겨운 최적화라도 해야 했던 것이다.

이런 여러 이유로 인해 16비트 Windows 시절에는 지금의 32/64비트보다 어셈블리어라든가 실시간 코드 생성 테크닉이 확실히 더 즐겨 쓰였던 것 같다.
외부에서 호출 가능한 콜백 함수를 지정하기 위해 껍데기 썽킹 함수를 생성해 주는 MakeProcInstance (해제하는 건 FreeProcInstance)부터가 그 예이며..

또 그때는 API 훅킹도 대놓고 훅킹 대상 함수 메모리 주소에다가 내 함수로 건너뛰는 인스트럭션을 덮어쓰는 식으로 행해졌다. 지금이야 이식성 빵점에 가상 메모리와 프로세스 별 메모리 보호, 멀티스레드 등 여러 이유 때문에 위험성이 크고 사용이 강력히 비추되는 테크닉으로 봉인됐지만 말이다.

Windows 95는 비록 32비트 명령어와 32비트 메모리 주소 공간을 사용하지만 GDI 계층은 여전히 16비트 코드를 쓰고 있으니 내부적으로 과거의 테크닉이 그대로 쓰였다. 그 당시의 PC 환경에서는 최고의 성능을 발휘했겠지만, 그리기 코드 자체의 32비트화, 좌표계의 32비트 확장이라든가 멀티스레드 대비 같은 건 전혀 불가능한 레거시로 전락할 수 밖에 없다.

그에 반해 Windows NT의 BitBlt는.. 이식성이 전혀 없는 기계어 코드 실시간 생성 같은 테크닉이 쓰였을 리가 만무하며, 어느 플랫폼을 대상으로나 동일하게 적용 가능한 C 코드로만 구현되었을 것이다. 겉으로 하는 동작은 비슷해 보여도 내부 구현은 완전히 달랐으며, 같은 사양의 PC에서 속도가 더 느린 것은 어쩔 수 없었다. 그 대신 NT의 코드는 플랫폼과 시대를 뛰어넘어 살아 남을 수 있었다.

뭐, 1990년대에는 OS/2도 얼리어답터들이 관심을 갖던 레알 32비트 운영체제이긴 했는데.. 얘는 Windows NT와 달리 32비트 계층도 코드가 전반적으로 그리 portable하지 않았다고 한다. 그러니 타 CPU로 포팅은 고사하고 훗날 같은 CPU에서 64비트에 대처하는 것도 유연하게 되기 어려웠으리라 여겨진다.

그에 반해, OS가 아니라 게임이긴 하다만 Doom은 Windows NT와 비슷하게(약간만 타이밍이 더 늦은) 1993년 말에 첫 출시됐는데.. 세계를 놀라게 한 3차원 그래픽을 실현했음에도 불구하고 어셈블리어를 거의 사용하지 않고 순수하게 C 코딩만 한 거라는 제작사의 증언에 업계가 더욱 충격에 빠졌다. 사운드처럼 상업용 라이브러리를 사용한 부분의 내부 구현을 제외한 전체 소스 코드가 수 년 뒤에 공개되면서 이 말이 사실이었음이 입증되었다.

도스에서 Doom을 가능케 한 것은 쑤제 어셈블리어 튜닝이 아니라 Watcom 같은 최적화 잘 해 주는 32비트 전용 C 컴파일러였다.
엔진 코드가 C로 나름 이식성 있게 깔끔하게 작성된 덕분에 Doom은 소스가 공개되자마자 오픈소스 진영의 덕후들에 의해 온갖 플랫폼으로 이식되면서 변종 엔진과 게임 MOD들이 파생돼 나올 수 있었다. 물론 소스 공개 이전에도 상업용으로 갖가지 플랫폼에 출시되기도 했고 말이다.

오늘날이야 컴퓨터 아키텍처라는 게 2, 30년 전 같은 춘추전국시대가 아니며, 가상 머신이라든가 웹 같은 환경도 발달해 있다. 그러니 "C언어는 이식성이 뛰어나다" 이런 식의 진술이 뭐 거짓말은 아니지만 약간 어폐가 있다. 하지만 BitBlt API부터 시작해서 이식성 있는 코드와 그렇지 않은 코드가 궁극적으로 어떤 상태가 되었는지를 생각해 보니 이 또한 의미 있는 일인 것 같다.

다시 Windows API 얘기로 돌아와서 글을 맺자면..

  • BitBlt는 비트맵 출력 API 중에서는 그나마 가장 기본적인 형태이다. StretchBlt는 비트맵을 크기를 변형(확대· 축소)해서 찍을 수 있다. 이들의 DIB 버전에 대응하는 것은 각각 SetDIBitsToDevice와 StretchDIBits이다.
  • TransparentBlt와 AlphaBlend는 아까 같은 AND/OR 래스터 연산 대신 color key 내지 알파 채널을 적용해서 투명색이 적용된 비트맵을 찍어 주는 함수이다. Windows 98/2000에서 새로 추가됐다. 본인은 사용해 본 적이 없다.
  • PatBlt는 원본 DC의 지정이 없이 브러시 패턴과 타겟 DC와의 래스터 연산만이 가능한 마이너 버전이다.
  • PlgBlt와 MaskBlt는 마스크 비트맵까지 한꺼번에 받아서 스프라이트 처리가 가능한 버전이다. 거기에다 PlgBlt는 일차변환을 적용해서 직사각형이 아닌 임의의 평행사변형 모양으로 비트맵을 찍을 수도 있는데.. Windows 9x에서는 지원되지 않고 NT에서만 존재해서 그런지 본인 역시 이런 함수가 있다는 걸 아주 최근에야 알게 됐다.

실무에서는 이렇게 비트맵을 한꺼번에 찍어 주는 함수를 쓰지, SetPixel이라든가 무식한 FloodFill 같은 기능은 그래픽 출력에서 쓸 일이 거의 없는 것 같다.
BitBlt과 유사 계열의 비트맵 출력 GDI 함수들은 비트 연산을 다루는 시대 배경에서 만들어진 만큼, 요즘 PNG 이미지처럼 비트맵 내부에 들어있는 알파 채널을 제대로 취급하지 못한다. 그리고 비트맵을 확대해서 출력할 때의 안티앨리어싱도 부드럽게 처리를 못 한다. 레거시 코드에다가 그런 기능까지 플래그로 넣기에는 너무 복잡하고 지저분해져서 그렇지 싶다. 그도 그럴 것이 GDI는 하드웨어 통합적으로 얼마나 추상적으로 설계되었던가?

현대의 화면 래스터 그래픽에서 필요로 하는 최신 기능들은 한때 GDI+가 따로 담당하다가 요즘은 그것도 너무 느리다고 도태됐고 Direct2D 같은 다른 패러다임으로 옮겨 갔다.

Posted by 사무엘

2018/03/10 08:37 2018/03/10 08:37
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1466

« Previous : 1 : ... 94 : 95 : 96 : 97 : 98 : 99 : 100 : 101 : 102 : ... 230 : Next »

블로그 이미지

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

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2026/07   »
      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:
3942186
Today:
1169
Yesterday:
1685