일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
[GGG] 일욜날 우연찮게 교보 문고 갈 있이 있었습니다. 서울역에 K를 바래다주러 갔다 간만에 오프라인 서점의 향기나 맡을겸 교보문고를 찾았죠. 제가 서울 근처에 살아서 좋은 점이 있다면 이렇게 큰 서점에 갈 수 있어서가 아닐까 하는 생각을 해봅니다. 부산에도 큰 서점은 많이 있지만 교보만한건 없죠. ㅎㅎ ![]() 역시나 새로운 책들이 많이 나왔더군요. 먼저 들른 곳은 컴퓨터 코너였습니다. 가장 먼저 눈에 들어오는 것은 "맨먼스 미신"이란 책 이었습니다. 굉장히 유명한 책이죠. "지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다."라는 법칙으로 더 유명한 책이기도 합니다. 유명한 책임에도 저는 아직 읽어보질 못했습니다. 주문한 책들을 다보고 나면 꼭 사서 읽어 보도록 해야 겠습니다. 서서 몇 장 봤는데 좋은 내용이 많은 것 같더군요. IT 업계의 고전이 아닐까 싶습니다. ![]() 저 책 좀 보다 바로 밑에 있는 "코드 한 줄 없는 IT 이야기"란 책을 보게 되었습니다. 마이크로소프트 이야기도 많고, IBM 이야기도 많고, 닷넷 이야기도 자바이야기도 많은 책이더군요. 아니나 다를까 김국현님이 저자시더군요. 김국현님의 블로그를 구독하는 저로써는 굉장히 반가웠습니다. 물론 개인적으로 알진 못하지만 ㅋㅋㅋㅋ 책 내용도 재미있게 잘 쓰셨더군요. 화장실에서 부담없이 읽기에 딱 좋은 분량인 것 같습니다. ![]() 제가 서점에 체류한 5~6시간 동안 진득하게 본 책은 다름 아닌 "내 몸 사용 설명서"란 책입니다. 우리 몸의 구석구석을 설명해 주는 책이죠. ㅋㅋㅋ 이런 책도 의외로 재밌더군요. 신체 부위별로 각 챕터가 구성되어 있습니다. 뇌, 심장, 소화기관, 호흡기, 머 이런 식이죠. 아마 몇 개 빼고는 대부분 다 읽은 것 같습니다. 대충 읽어서 그런지 읽을 때는 고개를 끄덕였는데, 읽고 나니 막상 기억에 남는게 없더군요. 한 권 사려다가 말았습니다. ㅎㅎ ![]() ![]() 제가 교보 문고를 나와서 다음날 주문한 책은 아래 두 권입니다. 유소영님의 "유소영의 영작 1교시"란 책과 신영복 님의 "강의: 나의 동양고전 독법"이란 책 입니다. 교보에서 영작 일교시를 보고 주문을 했는데 만원이 안돼서 강의를 같이 구매했습니다. 받아보니 두권다 좋네요. ㅎㅎ 영작 일교시는 영작을 잘 못하는 분들에게 많은 도움이 될 것 같습니다. 쉽고, 재밌고, 실용적으로 쓰여진것 같네요. ㅋ 강의는 동양 고전에 관한 책인데 다소 어렵습니다. 처음 부분을 조금 봤는데 시간을 두고 천천히 읽어야겠습니다. ![]() 끝으로 예약 구매로 받아본 따끈따끈한 책 입니다. 우리에게 ROOTKITS을 선물한 두 아저씨의 최신작입니다. 이름하연 "온라인 게임 뽀개기"입니다. 역시나 군더더기 없고 깔끔하고 황홀한 내용들을 보여주고 있습니다. 온라인 게임 해킹 관련 분야에 종사하는 분들에게는 많은 도움이 될 것 같네요. 별 필요없는 부분을 제외하고 절반정도 읽었는데 강추입니다. 나머지 부분을 다 읽으면 자세하게 서평을 쓰도록 하지요. 이 아저씨들 믿고 책 사셔도 됩니다. 절대 실망시키지 않을 거예요 ㅎㅎ 세상은 넓고 읽을건 많은 요즘입니다. *^^* |
[GGG] 신입 개발자를 위한 복잡한 포인터 선언을 해석하는 방법 신영진 pop@jiniya.net http://www.jiniya.net C언어 게시판에 자주 올라오는 질문 중에 하나가 복잡한 포인터 선언문을 해석하는 것들이다. 대부분의 학생들은 이것을 막연히 외우려고 한다. int *a[3]은 int 포인터를 저장하는 배열이고, int (*a)[3]은 int 배열에 대한 포인터라고 외우는 것이다. 하지만 이렇게 외운 지식은 그 형태가 조금만 달라져도 무용지물이 된다. 그렇다면 어떻게 해야 이러한 선언문을 손쉽게 해석할 수 있을까? 간단한 규칙만 이해하면 된다. 복잡한 선언을 정확하게 이해하기 위한 첫 단계는 선언문 내부에 나타나는 각 요소의 정확한 의미를 이해하는 것이다. <표 1>에는 선언문 내부에 나타나는 각 구성요소의 의미와 사용 예가 나와있다. 선언문을 해석할 때 영어를 이용하면 굉장히 편리하게 해석할 수 있다. 따라서 각 기호에 맞는 영어 표현도 같이 알아두는 것이 좋다. 표 1 표현식에 나타나는 기호들의 의미
다음으로 이해해야 하는 것은 선언문을 해석하는 순서다. 선언문은 선언 대상이 되는 변수 명에서 시작해서 오른쪽으로 가면서 해석한다. 선언문의 끝이나 오른쪽 괄호를 만나면 방향을 바꾸어 왼쪽으로 가면서 해석한다. 왼쪽으로 가면서 해석을 하다 왼쪽 괄호를 만나면 다시 오른쪽으로 가면서 해석한다. 이렇게 해서 선언문의 가장 왼쪽 끝에 도달하면 해석이 마무리 된다. 표 2 복잡한 표현식들의 해석 순서와 해석 결과
|
[GGG] 신입 개발자를 위한 메모리 사용법 2. 신영진 pop@jiniya.net http://www.jiniya.net 6월호 기사에서 우리는 함수로 넘어오는 인자와 함수의 리턴 값에 사용되는 메모리의 종류와 사용 방법에 대해서 배웠다. 하지만 실제 프로그램을 작성할 때에는 인자와 리턴 값 외에도 신경 쓸 부분이 많다. 이번 시간에는 Windows 메시지에 사용된 복잡한 특성의 메모리와 스마트 포인터를 사용해서 메모리 릭을 방지하는 방법에 대해서 살펴본다. 복잡한 특성을 가진 메모리 LVN_GETDISPINFO는 리스트 뷰 컨트롤에서 추가한 아이템의 내용을 콜백으로 설정하도록 했을 때 날라오는 메시지다. 이 메시지의 파라미터로는 LVITEM이 넘어온다. 대부분의 초급 Visual C++ 책에서는 이 메시지 핸들러에 다음과 같은 코드를 포함하고 있다. [CPP]strcpy(item->pszText, _T(“태권브이”));[/CPP]아주 단순한 코드다. 그런 만큼 책에는 저 코드에 대한 어떠한 설명도 없다. 하지만 우리는 저러한 코드를 보면 “pszText에 대한 할당과 해제를 책임지는 것은 누구일까?”라는 질문을 꼭 던져야 한다. pszText는 꽤나 복잡한 성격의 포인터다. 복사할 문자열의 길이가 cchTextMax보다 작다면 위와 같이 문자열 복사를 하면 된다. 만약 복사할 문자열이 더 길다면 pszText가 가리키는 포인터를 아래와 같이 바꾸어 주면 된다. 이 때 한 가지 주의해야 할 점은 pszText가 가리키고 있는 메모리가 적어도 두 번의 LVN_GETDISPINFO 메시지를 더 받은 다음 파괴되어야 한다는 점이다. [CPP]item->pszText = _T(“태권 브이”);[/CPP]위와 같이 복잡한 특성은 LVN_GETDISPINFO를 설계한 사람이 아니라면 알 수 없기 때문에 API를 만든 사람은 친절하게 매뉴얼에(MSDN) 설명을 적어 놓았다. 따라서 위와 같이 이상하게 보이는 메모리가 있다면 반드시 매뉴얼을 통해서 그 메모리를 다루는 방법에 대해서 숙지한 다음 사용하도록 해야 한다. 스마트 포인터 스마트 포인터는 RAII (Resource acquisition is initialization)의 개념을 가장 잘 활용한 예 중의 하나다. RAII란 생성자에서 자원을 획득하고, 소멸자에서 자원을 자동적으로 파괴해야 한다는 원칙이다. <리스트 1>을 살펴보자. 할당한 메모리 ptr이, some_condition인 경우는 해제되지 않고 리턴 하기 때문에 릭이 생긴다. 바보 같은 코드처럼 보이지만 할당된 자원이 많고, 함수가 복잡해질수록 이러한 일은 더욱 쉽게 일어난다. 이러한 문제점을 스마트 포인터를 사용해서 변경한 코드가 <리스트 2>다. <리스트 2>의 char_ptr은 동작원리를 보여주기 위해서 간단하게 제작된 것이다. 실제 스마트 포인터의 구현은 훨씬 더 복잡하다. 하지만 걱정할 것 없다. 표준 라이브러이의 auto_ptr이나 boost 라이브러리의 shared_ptr과 같이 잘 구현된 스마트 포인터 클래스가 많이 있기 때문이다. 리스트 1 스마트 포인터를 사용하지 않은 코드 [CPP]void func() { char *ptr = new char[20]; if(some_condition) return; delete [] ptr; }[/CPP]리스트 2 스마트 포인터를 사용한 코드 [CPP]class char_ptr { private: char *m_ptr; public: char_ptr(size_t size) { m_ptr = new char[size]; } ~char_ptr() { delete [] m_ptr; } operator char *() { return m_ptr; } }; void func() { char_ptr ptr(20); if(some_condition) return; }[/CPP] |
[GGG] 신입 개발자를 위한 메모리 사용법 1. 신영진 pop@jiniya.net http://www.jiniya.net 자본주의 사회에서는 자신의 것과 남의 것이 명확하게 구분된다. 허락 없이 남의 것을 가져가면 법적으로 처벌받는다. 이러한 원리는 컴퓨터 속 세상에도 동일하게 적용된다. 자신이 할당한 메모리가 아닌 곳을 임의로 사용하면 잘못된 연산이 수행되었다는 오류와 함께 프로그램은 종료된다. 따라서 메모리를 사용할 때에는 반드시 그 용도와 소유권을 분명히 알아야 한다. 하지만 불행하게도 C/C++은 그러한 것을 명확하게 할 수 있는 언어적 표현 방법이 존재하지 않는다. 여러 개의 변수를 동시에 리턴 할 수 없기에 함수 파라미터에 입력과 출력을 위한 것이 섞여서 사용된다. 또한 리턴 값으로 포인터가 사용되는 경우에도 그 포인터가 입력으로 들어간 파라미터의 포인터인지 누군가 내부적으로 할당한 포인터인지를 함수 원형을 통해서 알 수 있는 방법이 없다. 내 것과 남의 것이 마구 섞여서 사용되면서 누구의 것인지 표시가 없는 것과 같은 상황인 셈이다. 그래서 남의 메모리를 허락 없이 사용하고도 무엇이 잘못됐는지 모르는 일들이 벌어지곤 한다. 이런 실수를 방지하기 위해서 주의해야 할 것들에 대해서 알아보자. 파라미터의 용도 [CPP]BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo);[/CPP]위와 같은 함수 원형을 만났을 때 가장 먼저 생각해야 하는 것은 포인터 파라미터의 용도다. lpVersionInfo가 입력을 위한 것인지 출력을 위한 것인지 아니면 둘 다를 위한 것인지를 가장 먼저 판단해야 한다. 입력을 위한 것은 구조체 값을 참조만 하고 변경하지 않음을 의미한다. 출력을 위한 것은 아무 구조체나 할당된 것을 그냥 집어 넣으면 적절한 값으로 구조체를 채워 줌을 의미한다. 가장 복잡한 입출력은 구조체의 일부 멤버를 사전에 설정해서 넘겨주면 함수 내부에서 나머지 멤버를 적절한 값으로 채워서 넣어준다는 것을 의미한다. 새로운 함수를 만나면 항상 포인터 파라미터가 세 가지 중에 어디에 속하는지 파악하고 그 목적에 맞는 포인터를 파라미터로 넘겨 주어야 한다. GetVersionEx함수의 lpVersionInfo는 입, 출력을 위한 파라미터다. 함수를 호출하기 전에 반드시 dwVersionInfoSize에 구조체 크기를 저장한 다음 함수로 넘겨 주어야 한다. 리턴 값의 출처 [CPP]struct tm *localtime(const time_t *timer);[/CPP]C언어에서 시간을 구할 때 사용하는 localtime의 원형이다. 적어도 C언어를 제대로 배운 사람이라면 이런 함수의 원형을 만나면 리턴 값의 출처에 대해서 의심을 해야 한다. 리턴 되는 포인터를 누가 할당한 것인지, 해제를 누가 어떻게 하는 것인지에 대해서 정확하게 알아야 한다. 일반적으로 리턴 되는 포인터는 크게 다섯 가지 부류로 나뉜다. 각 부류의 대표 함수와 특징이 <표 1>에 나와있다. 물론 이 다섯 가지 범위 밖의 일반적이지 않은 함수들도 존재한다. 그러한 함수들에 대해서는 반드시 포인터의 출처를 함수 매뉴얼을 통해서 숙지한 후 사용해야 한다. 표 1 리턴 포인터의 종류
|