NEW에 대한 고찰

오늘날처럼 세상이 급변하고, 자고 일어나면 새로운 게 쏟아져 나오고, 사람들 역시 뭔가 새로운 것에 목말라 있던 적은 역사상 없었지 싶다. 그런데 성경에 따르면 그런 트렌드 자체도 그렇게 새삼스러운 것만은 아닌 것 같다.

모든 아테네 사람들과 거기 있던 나그네들은 새로운 어떤 것을 말하고 듣는 것 외에는 자기들의 시간을 달리 쓰지 아니하였더라. (행 17:21)

성경 66권 각 책들이 모두 개성이 넘치는 책이긴 하지만, 본인은 사도행전이 문체와 표현이 굉장히 독특하다는 생각을 해 왔다. 성경은 사도행전에서, IT 시대가 도래하기 전부터 이미 얼리어답터라는 집단이 있었음을 보여준다. 맨날 뭔가 새로운 트렌드, 조금이라도 더 창의적인 개똥철학에 탐닉하는 사람들이었다.

새로운 것과 관련된 언어 현상을 먼저 좀 살펴보기로 하자.
new에 대응하는 한국어는 원래 ‘새롭다’라는 형용사인데, 신기하게도 ‘새’만 써도 관형사로서 ‘새롭다’라는 뜻이 된다. 그래서 유명한 컴퓨터 개그가 있다.

“교수님, 새에 대해서 논문이라도 쓰시나 보죠?” (레 11:13-19 같은?)
“아니. 파일을 ‘새 이름으로’ 저장해야 한다는데, 이젠 더 생각나는 새 이름이 도저히 없어서 고민일세.”


영어권의 “Press any key...” / “any라는 키가 도대체 어디 있지?” 개그와 쌍벽을 이루는 한국식 컴퓨터 개그가 아닐 수 없다. 썰렁했다면 죄송. ㄲㄲㄲㄲㄲㄲㄲㄲㄲ

사실, GUI 환경에서는 각종 메시지 박스는 반드시 ‘확인’(OK) 버튼을 클릭해야 하고, 이 버튼은 Space나 엔터로만 인식이 되니까 Press any key 같은 메시지를 볼 일은 없어졌다. 명령창(command prompt; console) 환경에서나 볼 수 있다.
요즘 소프트웨어들은 새 이름 같은 악명 높은 오해(?)를 원천적으로 없애기 위해, ‘새’ 대신 ‘다른 이름으로 저장’이라는 표현을 써 주고 있다는 것도 알아 두자. ^^;;

하나 더, 본인은 한국어에서 ‘기존’이라는 표현이 오· 남용되고 있는 게 개인적으로 굉장히 거슬린다. ‘예전’, ‘종전’이라는 표현이 싹 다 저걸로 통합되는 경향이 있다. 기존이란, 현존(현재 존재)· 실존(실제로 존재)만큼이나 ‘이미 존재’라는 뜻일 뿐이다. “기존하는 아이템”처럼 활용도 가능하다. 그런데 “기존에 있는 것은 지우세요”는 도대체 뭐란 말이냐. 역전앞, 프린터기보다 더 말이 안 되는 표현이다.

‘기존’이라는 말을 제일 널리 퍼뜨리고, 또 잘못 퍼뜨리기도 한 곳이 IT계가 아닐까 하는 게 본인의 생각이다. 맨날 업그레이드, 업데이트를 밥 먹듯이 하는 분야이다 보니 늘 예전 것과 비교를 하고 뭔가 새롭다는 걸 강조해야 하기 때문이다.
물론, 굳이 IT계가 아니어도 자동차계도 차 이름 앞에다 new를 붙이는 게 유행이었다. 뉴 엑셀, 뉴 소나타, 뉴 프린스, 뉴 그랜저... 그러고 보니 포니는 ‘뉴 포니’가 아니고 ‘포니 2’였는데, 나중엔 네이밍 방식이 바뀌었다.

하지만 new가 붙고 화려하게 세상에 드러난 그 이름들이 세월이 흐르고는 어떻게 되었을까? 분야별로 살펴보면 재미있다.

사용자 삽입 이미지
1991년에 출시된 MS-DOS 5.0의 미국 현지 CF의 한 장면이다. “It's new!!” 출처는 유튜브.
1985년에 스티브 발머가 온갖 오버액션으로 윈도우 1.0 광고 개그를 펼치던 동영상만큼이나 웃기다.

1. NE
오늘날 마이크로소프트 사의 윈도우 운영체제는 90%가 넘는 점유율로 PC 환경을 완전히 평정했다.
그런데 지금으로부터 15~20년 가까이 전에 역사 속으로 사라진 윈도우 1.0부터 3.x까지의 16비트 시절에 쓰이던 자체 실행 파일의 이름은.. New Executable이었다! 32 내지 64비트 시대가 된 오늘날에 이 실행 파일 포맷이 새롭다고 생각하는 사람은 아무도 없을 것이다. (지금은 Portable Executable이라는 다른 포맷이 쓰임)

사용자 삽입 이미지

2. NDC

사용자 삽입 이미지사용자 삽입 이미지
위의 사진은 1984년에 도입되어 20년 남짓 국내에서 운행된 무궁화호 디젤 동차(기관차 견인형이 아니고)인데, 업계 종사자 내지 철도 동호인들이 부른 명칭은 NDC. 신형 디젤 동차(New Diesel Car)였다. 1984년에 철도청이 저런 CF를 찍던 당시에는 아주 새로운 차량이었으나, 지금은?
사용자 삽입 이미지
2006년부터 폐차가 진행되어 지금 NDC는 완전히 역사 속으로 사라졌다. 지못미 NDC.
출처: 류 기윤(현직 코레일 기관사 겸 철도 동호인) 님의 블로그

3. NIV, NASV, NRSV, NKJV 등등..;;
드디어 KJV 크리스천들에게 아주 친숙한 이름들이 나왔다.
new라는 이름이 유난히도 자주 눈에 띄는 분야는 다름 아닌 성경 역본이다.
물론 본인 같은 사람은 그런 것들을 변개된 old lie일 뿐이라고 폄하하지만 말이다.
참고로 과거 통근열차(CDC)를 무궁화호로 개조하여 2008년부터 NDC의 후속 차량으로 뛰고 있는 열차는 RDC라고 불리고 있는데, KJV 신자들이 싫어하는 RV, RSV의 R과 같은 의미의 이니셜이다. Revised와 New는 여러 분야에서 통용되는 단어임이 틀림없다. ^^;;

이런 역사로부터 얻을 수 있는 큰 교훈이 있다.
지금 당장은 새롭다고, 참신하다고 new라고 상업적으로 막 떠벌려진 것들도.. 세월이 흐르면 그다지 대수롭지 않은 게 태반이며, 결국 인간은 동일한 패턴의 쳇바퀴를 돌고 있을 뿐이라는 것. 성경의 그 유명한 말씀에 공감하게 된다.

이미 있던 것 즉 그것이 후에 있겠고 이미 행한 것을 후에 다시 행하리니 해 아래에는 새 것이 전혀 없도다. (전 1:9)

자칭 이종 예술가로 활동 중인 김 형태 씨의 칼럼을 읽어보면 글쓴이가 저런 면에서 상당한 통찰력이 있는 분임을 알 수 있다. 기타 다른 주제의 글에서 느껴지는 인본주의· 자유주의적인 견해가 성경의 사고방식에서 왔다고 보기는 어렵지만, 옛날과 오늘날이라든가 옛 것과 새 것의 관계에 대해서는 영적으로 아주 잘 간파했다.

... 과거에 비해서 현재가 여러가지 의미로 더 좋아진 것은 분명하지만, 결국 문화, 예술, 철학은 오늘도 옛것을 계속 리메이크하면서 팔고 있는 것이 현실이다.

... 누군가 저에게 반문했죠? 정말 이 시대보다 옛날이 더 좋았다고 생각하느냐고. 문화와 역사에 대해 조금만 지식이 있으면 당연한 소리입니다. 아무 분야나 하나 잡아서 그 분야의 전문가에게 물어보세요. 20년, 30년 전, 40년 전, 50년 전에 비해서 지금이 더 좋은 시절이냐고. 음악, 패션, 건축, 디자인, 가구, 자동차, 경제구조, 세계 평화, 문학, 미술, 레크리에이션, 철학, 스포츠 등등 알고 보면 좋은 시절은 다 갔다고 말해도 과언이 아닐 정도입니다.


이 시대를 사는 젊은이들에게 던지는 따끔하지만 유익한 고언, 충고, 조언이 많으니 칼럼을 진지하게 읽어보기 바란다.
그래서 성경은 이렇게 말한다.

{주}가 이같이 말하노라. 너희는 길들 가운데 서서 보며 옛 행로들 곧 선한 길이 어디 있는지 물어보고 그 길로 걸으라. 그리하면 너희가 너희 혼들을 위한 안식을 얻으리라. ... (렘 6:16)

굳이 이 구절과 비슷한 사상이 담긴 사자성어를 찾자면 온고지신인데...
이 말은 당연한 말이지만 세상의 변화를 무조건 배척하고 거들떠보지도 않으면서 수구꼴통이 돼라는 소리가 아니다. 그런 극단으로 치우치면, 문명의 이기를 다 거부하고 생체 이식 칩과 신용카드가 666이라는 논리로 빠지게 된다.

말씀이 의도하는 바는, 언뜻 보기에 구시대적이고 수구꼴통(?) 같지만 결국 인간 세상이 유지되는 데 필요한, 그 검증되고 안정화된 성경적인 길을 일단 존중하고 따라 걸으라는 뜻이다. 그런 것들이 괜히 아무 이유 없이 존재한 게 아니기 때문이다.

새로운 것 중에 진짜로 새로운 건 극히 드물다. 인생의 법칙은 불변이며, 결국은 하나 좋은 걸 만들었다면 이를 위해 다른 하나를 반드시 희생했다는 식으로 대가가 있을 것이기 때문에 이를 잘 분별해야 한다. 세상에 공짜란 없다. 상업적인 광고는 그런 이면의 그림자를 소비자에게 절대로 솔직하게 보여주지 않는다. 그런 행간의 의미를 읽는 게 인생의 지혜이며, 오늘날 우리에게 매우 필요한 능력 중 하나임이 틀림없다. 여기에 대해서도 분야별로 여러 case study를 제시할 수 있으나, 시간과 분량 관계상 거기까지는 생략하겠다.

성경에서 하나님이 인정하는 진짜 NEW란, 사람이 거듭나서 구원받은 후 바뀐 행적이고, 훗날 이 땅에 세워지는 새로운 왕국이며, 나중에 창조될 새 하늘과 새 땅이다. 종교적이고 상징적인 의미로만 new가 아니라 저게 진짜로 객관적으로 new이다. 새로운 것에 목말라 있는 분이라면 역설적으로 성경이 제시하는 옛 길을 반드시 고려해 봐야 할 것이다.

Posted by 사무엘

2010/12/15 18:49 2010/12/15 18:49
, , , , ,
Response
No Trackback , 13 Comments
RSS :
http://moogi.new21.org/tc/rss/response/431

C 언어는 다른 언어가 언어 차원에서 기본으로 제공해 주는 상식적인 기능이 없고, 대신 별도의 함수 호출에 의존하는 형태인 게 몇 가지 있다. 거듭제곱 연산이 대표적인 예이고, 문자열 타입도 언어가 자체 제공하지 않는다. 사실은 동적(힙) 메모리를 할당하는 기능 자체가 아예 없다.

그 이유는 간단하다. 저런 기능들은 컴퓨터 CPU 명령 차원에서 직관적으로 구현 가능하지 않기 때문이다. 그래서 연산자가 그렇게도 많다는 C 언어는 거듭제곱 연산자가 없으며 pow라는 함수를 호출해야 한다. (그나마 파스칼은 그런 함수조차도 없기 때문에, exp와 log 함수 조합으로 임의의 수의 거듭제곱을 얻어내야 한다.)

메모리 할당도 마찬가지이다. 메모리 관리는 CPU뿐만이 아니라 해당 운영체제/플랫폼이 담당하는 비중도 크기 때문에, 작은 언어인 C가 언어 차원에서 자체 제공하지는 않는 것이다. malloc, free, realloc 같은 함수를 써야 한다. 그러면 윈도우 운영체제의 C 라이브러리는 내부적으로 또 HeapCreate, HeapAlloc 같은 더 저수준의 윈도우 API를 이용해서 그런 메모리 관리 기능을 구현해 준다.

그런데 C++에서는 드디어 동적 메모리 할당과 해제 기능이 언어 차원에서 연산자로 추가되었다. 바로 new와 delete 연산자이다. 그때까지 영단어로 이루어진 연산자는 sizeof가 고작이던 것이 새로 추가되었으며, 그 후로 *_cast라든가 typeid 등 여러 영단어 연산자가 C++에 추가되었다. 메모리 할당이라면 몰라도 개체의 생성과 소멸에 따른 생성자와 소멸자 함수 호출은 언어 차원에서 책임져 줘야 하는 영역이기 때문에 별도의 연산자가 생긴 것이다.

연산자가 추가된 덕분에 일단 type casting이나 sizeof 계산을 할 필요가 없게 된 것은 좋다.

pData = new DATA[nCount];
pData = (DATA *)malloc(sizeof(DATA)*nCount);

물론 번거로운 문법 정도야 C 시절에도 매크로로 대체 가능했겠지만 말이다.

#define NEW_C(T, N)  (T *)malloc(sizeof(T)*(N))

그러나 new 연산자는 malloc 함수처럼 범용적인 void* 포인터를 되돌리는 건 지원하지 않으며, 해당 타입의 배수가 아닌 크기의 메모리도 할당할 수 없다. 그렇기 때문에 가변 길이 구조체 같은 메모리를 할당하는 건 오히려 더 불편할 수 있다.
또한 할당 아니면 해제만 지원되지 C 함수처럼 realloc 기능도 없다. C++의 메모리 연산자는 오로지 개체의 생성과 소멸에만 초점을 둔 것이다. 그렇기 때문에 이것이 기존 C의 메모리 관리 함수를 완전히 대체하지는 못할 것으로 보인다.

new 연산자로 데이터 타입을 지정한 뒤에는 new DATA[100] 처럼 배열 첨자가 올 수 있고, 아니면 new Object(x, y)처럼 해당 개체의 생성자 함수에다 넘겨 줄 인자가 올 수도 있다. 두 문법 중 오로지 하나만 허용된다.
그러므로 생성될 때 생성자 함수 인자 전달이 필요한 개체는 배열로 만들 수 없다. 그러나 인자가 필요한 생성자 함수가 존재한다 할지라도, 전부 default argument가 있어서 대체가 가능하다면 배열을 만들 수 있다.

1. new operator vs operator new

이 new 연산자(new operator)는 내부적으로 operator new라는 함수를 호출하는 형태로 구현되어 있으며, 이 특수한 함수는 나름 오버로딩이 가능하다! (delete도 마찬가지) 비록 개체를 생성하여 생성자 함수를 호출한다는 기본 기능은 C++의 특성상 불변이지만, 이 연산자가 하는 일 중 메모리를 할당하고 해제하는 계층은 customize가 된다는 뜻이다.

void *operator new(size_t size);
void operator delete(void *ptr);

operator new 함수는 첫째 인자는 무조건 포인터 크기와 같은 부호 없는 정수형이어야 한다. 부호 있는 정수형도 허용되지 않는다. 그리고 리턴값은 void *이어야 한다.
한편 delete 함수는 첫째 인자는 무조건 void *이어야 하고, 함수의 리턴값은 void여야 한다. 일단 기본적인 생김새는 malloc, free와 완전히 일치한다는 뜻.

당연한 말이지만 이 함수만 단독 호출이 가능하다.
malloc(100)을 쓸 곳에 그냥 operator new(100) 이라고만 써도 된다. 그러면 어차피 new char[100]과 비슷한 효과가 나게 된다. C++ 언어는 이 함수들의 기본 구현을 라이브러리 차원에서 제공하고 있다. 만약 기본 C/C++ 라이브러리를 사용하지 않으면서 new/delete 연산자도 쓰고 싶다면 내가 직접 이들 함수를 구현해 줘야 한다.

거기에다 나만의 인자를 추가한 operator new/delete를 만들 수 있다. 예를 들어, C/C++ 라이브러리가 사용하는 프로세스 기본 힙이 아닌 다른 곳에다가 메모리를 할당하고 싶다면 이렇게 코드를 써 주면 된다.

void *operator new(size_t size, HANDLE hHeap)
{ return HeapAlloc(hHeap, 0, size); }

HANDLE hMyHeap = HeapCreate( ... );
Object *pt = new(hMyHeap) Object( ... );

new 바로 옆에다가 전달해 주는 인자는 operator new의 둘째 이후의 인자로 전달된다. delete도 비슷한 방식으로 오버로딩 가능하다. 놀랍지 않은지?

모든 개체과 기본 자료형에서 통용되는 global scope의 operator new/delete가 있는 반면, 특정 클래스에서만 통용되는 new/delete 함수를 만들 수도 있다. 함수 프로토타입은 동일하다. 이 new/delete 함수는 굳이 static을 지정해 주지 않더라도 언제나 static으로만 선언되기 때문에, 클래스 내부에 있더라도 가상 함수 지정이나 this 포인터는 지원되지 않는다. 또한 생성자· 소멸자· 대입 연산자 등과는 달리, 파생 클래스로 상속도 된다.

2. new operator vs new[] operator

그런데, 더욱 충공깽한 사실은 new와 new[] (delete도 delete[])가 구분되어 있다는 것. 이런 구분이 언제 필요하냐 하면 소멸자 함수가 존재하는 개체의 배열을 선언할 때이다. (물론 기본 자료형이 아니라 개체를 배열로 만드는 경우는 드물지만 말이다.)
우리가 요청하는 메모리의 크기와 실제로 운영체제로부터 할당되는 메모리의 크기는 여러 가지 요인으로 인해 일치하지 않는 경우가 있으며 후자가 전자보다 대체로 더 크게 잡힌다.

배열을 delete로 해제할 때는 여기에 있던 배열 각 원소들에 대해서도 소멸자 함수를 일일이 호출해 줘야 하는데, 원래 여기에 개체가 정확하게 몇 개 있었는지를 메모리 블록만 봐서는 알 수 없게 되는 것이다.
그래서 1980년대에 C++이 처음 등장했을 때는 delete 연산자에다가 배열의 개수까지 지정을 해 줘야 했다.

int *arr = new int[nCount];
Object *ptr = new Object[nCount];
(....)
delete arr; //기본 자료형은 그냥 이렇게 지워도 무방
delete[nCount] ptr; //이놈은 흠좀무

C++은 그렇잖아도 garbage collector도 없어서 불편해 죽겠는데 배열의 원소 개수까지 프로그래머가 관리해야 한다니, 이게 말이나 되는 소리인가?

프로그래머의 원성이 빗발친 덕분에 시스템이 바뀌었다. 배열의 원소 개수는 C++이 메모리를 할당하면서 내부적으로 알아서 관리하도록 바뀌고 원소 개수를 생략 가능해졌다. 그러나 그래도 이게 배열이라는 힌트는 알아서 줘야 한다. 배열일 때와 그렇지 않을 때 C++이 메모리를 관리하고 인식하는 방식은 여전히 서로 약간 다르기 때문이다.

delete arr; delete[] ptr; 를 해도 괜찮다는 소리이지 delete arr; delete ptr; 처럼 구분이 완전히 사라진 건 아니다.

그래서 operator new/delete를 오버로드했다면 operator new[]/delete[]의 오버로드도 지원된다. 둘은 인자의 의미나 하는 일의 차이는 전혀 없다. 단지 new[]의 경우, 연산자의 리턴값 포인터에다가 곧바로 개체가 저장되지는 않는다는 차이가 존재할 뿐이다. 배열 원소 개수가 앞부분에 먼저 저장되고 그 뒤의 공간부터가 쓰인다.

자바와 C#에서 볼 수 있듯, 요즘 대세는 개체는 무조건 new로 선언하는 것이다. 그게 언어 문법까지 더 명료하게 만들어 주는 효과까지 있다. 그러나 C++은 기본 자료형이든 개체든 스택과 힙에 모두 선언 가능하고, 심지어 함수 전달도 둘 다 call by name이나 reference 방식이 모두 가능하다.

일반적으로 컴파일러들은 C++의 operator new/delete도 내부적으로는 C의 malloc/free로 구현한다. 기능이 완전히 동일한데 둘의 동작 방식이 달라야 할 이유가 전혀 없기 때문이다. 그러나 원칙대로라면 malloc으로 할당한 포인터를 delete로 해제한다거나, new로 할당한 메모리를 free로 해제하는 것은 허용되지 않는 비추 행동이다. 그렇게 섞어 쓰지는 않는 게 좋겠다.

Posted by 사무엘

2010/07/28 08:27 2010/07/28 08:27
, ,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/332


블로그 이미지

철도를 명절 때에나 떠오르는 4대 교통수단 중 하나로만 아는 것은, 예수님을 사대성인· 성인군자 중 하나로만 아는 것과 같다.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

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

Site Stats

Total hits:
1441867
Today:
161
Yesterday:
490