Skip to main content

Posts

Showing posts from April, 2007

C++ of the Day #40 - Python의 OptionParser 클래스 따라잡기

텍스트 기반 프로그램을 만들때 필요한 기능중의 하나가 command line option들을 parsing 해주는 것입니다. 원래는 boost::program_options 라이브러리 를 소개하는 글을 쓰려고 했습니다. 그런데 마침 Python을 사용하면서 알게 된 OptionParser 클래스 가 좀 더 사용하기가 쉬운 것 같아 이 클래스를 C++ 버전으로 만들어 보았습니다. boost::program_options 라이브러리와는 달리 옵션들의 grouping 이나 설정 파일을 사용하는 기능 은 구현되어 있지 않습니다. 그리고 옵션들의 타입은 모두 string이나 vector<string>을 사용합니다. boost::program_options과 같이 as<int> 하는 식의 함수를 제공할 수도 있었습니다만 이렇게 하려면 exception들을 정의해야 하기 때문에 생략하였습니다. 필요하다면 다음과 같이 boost::lexical_cast를 사용하면 됩니다. int blocksize = boost::lexical_cast (opts.get(BlockSizeOpt)); 그리고 OptionParser 클래스는 getopt_long을 사용하여 구현되었기 때문에 parsing하는 방법은 GNU coding standards 를 따릅니다. Command line option에는 short form과 long form이 있습니다. 예를 들어 -I는 short form, --include-path는 long form입니다. 또한 어떤 옵션은 여러개의 값을 가질 수도 있습니다. gcc의 -I 옵션은 여러개의 값을 가질 수 있는 옵션의 예입니다. 그럼 이제 OptionParser의 사용법을 하나씩 알아보겠습니다. 먼저 OptionParser를 다음과 같이 생성합니다. OptionParser op("Usage: %prog [options] arg1 arg2 ...", // usage "1.0",

Bad smell in mind

Refactoring을 읽어 보면 bad smell in code 라는 말이 나옵니다. 코드에서 나쁜 냄새가 느껴질 때가 refactoring을 해야 할 때라는 내용이죠. 예전에 했던 생각인데 bad smell을 꼭 코드에서만 맡을 수 있는 것은 아닌 것 같습니다. 제목에 쓴 것처럼 뭔가 심리적인 bad smell이 있을 것 같은데 제가 생각했던 한가지 bad smell in mind는 바로 이것입니다. 내 코드를 남들에게 보여주기 부끄럽다. 이 냄새를 맡게 되면 역시 refactoing을 시작해야 합니다. 보통은 주석을 통한 탈취 처리로 마무리되는 경우가 많지만 말이죠. 저는 예전보다는 이 냄새를 자주 맡을 수 없게 되었는데 이유를 생각해 보니 다음 중 하나일 것 같습니다. 나이가 한살 두살 많아지며 부끄러운 줄 모르게 되었다. 8-O 코드를 정말 잘 작성하게 되었다. 주변에 내 코드에서 냄새를 맡을 수 있는 사람이 없다. 제발 1번은 아니었으면 하는 것이 개인적인 바램. 물론 2번이었으면 하는데 이것도 썩 믿기질 않습니다. 결국 이유는 3번인 것 같습니다. 주변 사람들이 내가 코딩을 엉망으로 해놔도 엉망인지 알아보는 사람이 없다면 부끄럽지도 않겠죠. 실력있는 사람들 옆에 있으면 특별히 배우는 것 없어도 발전할 수 있는 이유중의 하나가 이런 것이 아닌가 합니다. 그들의 작업만큼 멋지지 않은 내 것을 보고 부끄러움을 느끼고 더 잘 하려고 노력하는 것만으로도 스스로 발전하는 것이죠. 처음 입사할 때는 대기업에 가면 훌륭한 개발자들이 많이 있겠지라는 생각을 했었습니다. 하지만 지금은 역시 대기업은 평균보다 약간 높은 수준의 인력을 관리 하여 제품을 개발하는 곳이구나라는 생각을 합니다. 물론 대기업에서 배울 수 있는 많은 것들이 있습니다. 큰 프로젝트 경험, 비싼 툴들, 관리 능력, 회사 생활, 인간 관계등등. 이중에서 제일 만족하고 있는 부분은 역시 큰 프로젝트 경험입니다. 100 man-year보다 큰 프로젝트들을 작은 회사에서 해보긴 어려울테니까

assert()와 NDEBUG

바로 이전 글에서 "디버깅 옵션으로 컴파일하니 문제가 없어져요"와 같은 주장을 엉뚱하다고 써놓고 제가 바로 그런 실수를 했네요. :-| 물론 이전 글과 같이 multi-threading 환경에서의 문제는 미묘한 타이밍 문제를 말하는 것이었지만 제가 한 실수는 바로 assert()와 관련이 있습니다. 모든 C/C++ 책들에서 경고하듯이 assert() 안에는 실제 동작해야 하는 코드가 들어가서는 안되죠. 제가 한 실수는 바로 아래 보이는 코드입니다. assert(pingback_.activate()); 서버로부터 오는 ping 메시지에 응답하는 thread를 동작시키는 코드입니다. 몇 주전 코드 테스트시에는 -g 옵션이 있어 이 코드가 제대로 동작을 했지요. 그런데 실제 환경에서 실행시켜보니 정확히 3분 30초마다 connection이 끊겼습니다. 서버와 클라이언트 사이의 ping 메시지에 문제가 있다고는 생각했지만 이전에 테스트했던 코드라 코드에 문제가 있으리라곤 생각도 안했지요. 정말 사람 눈에는 믿는대로 보이는 것인지 문제의 라인을 여러번 훑어 봤지만 보이질 않더군요. 결국 퇴근해서 집에 가는 버스안에서 생각이 나서 다음날 수정할 수 있었습니다. 물론 아직 제가 만들어서 저희 팀내에서만 테스트하는 코드라 큰 문제는 없었지만 옆 팀까지 사용하고 난 이후에 발생했으면 좀 부끄러웠겠네요. :roll: 한가지 더... 왜 assert는 NDEBUG일때만 동작하는 유일한 매크로이면서 ASSERT와 같이 대문자를 사용하지 않았는지 좀 원망스럽습니다. :-x

Low-Level Envy

Paul Graham이 쓴 Hackers and Painters 라는 글을 보면 math envy라는 말이 나옵니다. 과학계에 있는 사람들은 속으로 수학자들이 자신들보다 똑똑하다고 믿는 것을 두고 나온 말입니다. 이런 생각의 결과로 자신의 작업을 되도록이면 수학적으로 보이려고 애쓰게 되는데 물리학같은 과학에선 이런 현상이 별 해가 없지만 자연과학에서 멀어질수록 문제를 발생시킬 수 있습니다. 정말 중요한 문제보단 수학적으로 보일 수 있는 문제를 풀려는 유혹이 강해진다는 것이죠. 제 생각에 개발자들에게 또 하나의 envy가 있다면 low-level envy가 아닐까 합니다. C++를 알다보면 컴파일러의 구현 방법에 대해 알고 싶어집니다. 표준 라이브러리를 사용하다보면 이 함수는 어떤 시스템 콜을 사용하는지 궁금해지고요. 다음으론 그 시스템 콜은 커널에서 어떻게 동작하는지, 커널이나 디바이스 드라이버는 어떻게 구현되는지, 하드웨어와는 어떻게 인터페이스하는지, CPU는 한 명령어를 어떻게 처리하는지, 캐시는 어떻게 사용되는지 등등. 사실 이런 low-level envy는 math envy와는 달리 실제 프로그래밍 작업에 많은 도움이 됩니다. 실제 지난 글 에서 살펴봤던 pure virtual function called와 같은 에러는 컴파일러가 vtbl과 vptr를 어떻게 구현하는지를 몰랐다면 원인을 찾기가 어려웠을 것입니다. 다른 예로 시스템의 메모리는 남아 있는데 왜 더 이상 쓰레드 생성이 안되는지와 같은 에러의 원인을 알려면 커널이 어떻게 쓰레드를 구현하고 있는지를 알고 있어야 할 것입니다. C++ and the Perils of Double-Checked Locking 과 같은 문제점을 찾으려면 sequence point라는 개념과 컴파일러와 CPU에 의한 최적화 방법들까지 어느 정도 알고 있어야 합니다. 이런 low-level의 지식들은 날마다 필요한 것들은 아닙니다. 하지만 진짜 어려운 문제를 만났을 때 그것을 해결할 수 있느냐 없느냐의 차이를 가져옵니다

The C Programming Language

이제야 이 책을 읽었습니다. "The C Programming Language." 대학교에 가서 처음 배운 프로그래밍 언어가 f77을 가지고 배웠던 포트란이었는데 사실 기억나는 것도 별로 없고요, 다음이 C 였는데 배우면서 바로 C++이란 것을 알게 되어 그 뒤로는 계속 C++만 써왔습니다. 막연히 C야 다 안다고 생각해 왔던게 사실입니다. 원래 C++가 C with classes로 시작했던 것과는 반대로 저는 C를 C++ without classes로 생각해 왔었던 것이죠. :-| 개인적으로 요새 프로그래밍 언어들의 역할과 위치에 대한 관심이 높아져서 이것 저것 생각하고 있습니다. 그러다보니 프로그래밍 언어는 C랑 lisp만 있으면 되는것 아닐까라는 생각을 하게 되더군요. (충분한 low-level 언어 하나와 최고 high-level 언어 하나) 그러면서 혹시 C의 자리는 C++가 대신 할 수 없을까 하는 생각에 C도 한번 다시 보게 되었습니다. 읽어 보니 정말 별 다섯개짜리더군요. 학교에서 왜 C를 이 책으로 안 가르쳤을까라는 생각이 들더군요. 가장 인상 깊었던 점은 역시 그 깔끔함입니다. 책 전체를 통틀어 군더더기가 한 단어도 없더군요. 이 책을 읽고나서야 왜 GNU의 훌륭한 많은 툴들이 C로 작성될까라는 의문점이 조금은 풀렸습니다. C++는 C에 비해 fat하다고 생각하는 것 같아요. C 코드들은 한문장 한문장 꼼꼼히 생각해서 간결하게 작성된 느낌이고 C++는 encapsulation을 통해서 쉽게 작성된 대신 한문장 한문장에 쏟던 정성은 좀 덜한 것이죠. 이 책을 읽고 깨닫게 된 또 한가지 사실. The X Programming Language 라는 제목을 달고 나오는 책은 모두 그 언어를 만든 사람이 썼다는 점입니다. 아마 이 The C Programming Language에 바치는 오마쥬같은 것일까요. 간단히 찾아본 결과 C++, Java, C#이 이 제목을 가지고 있고 모두 저자 혹은 저자 목록에 언어의 설계자인 Bjarne

Core Dump Pattern 두번째

Code Dump Pattern에 대해서는 지난 번 글 에서 얘기한 바 있습니다. 한동안 잠잠하다가 다시 core dump가 발생했는데 이번에도 제가 담당하는 부분이 아니어서 보지 않고 있다가 다른 분이 pstack을 구해 공지한 것을 보니 대략 원인이 보이더군요. 그럼 먼저 증상을 보여 드릴테니 원인을 찾아보세요. :-) 먼저 log 파일에는 pure virtual function called 라는 문장이 출력되었으며 해당 pstack은 다음과 같았습니다. Thread 127 (process 18441): ... #17 0x01089514 in std::terminate () from /usr/lib/libstdc++.so.5 #18 0x01089a17 in __cxa_pure_virtual () from /usr/lib/libstdc++.so.5 #19 0x08ebc0d9 in DpOMidCallActiveInitial::process (this=0x555ff748, bcsm=0x89faec1c) #20 0x08e2bd77 in Bcsm (this=0x89faec1c, bcsmState=_DpOMidCallActiveInitial, legId=1, destinationRoutingAddress=0x0, cs=0x8f88aa14, isArmedTDPExist=true) #21 0x08e50e51 in BcsmKo (this=0x89faec1c, st=_DpOMidCallActiveInitial, lt=1, ds=0x0, cs=0x8f88aa14) #22 0x081eda42 in NPFactory::makeNewBcsm (st=_DpOMidCallActiveInitial, lt=1, ds=0x0, cs=0x8f88aa14, isArmedTDBExist=true) ... . 찾으셨나요? 사실 몇주 전에 pure virtual function called 에러에 관한 글을 쓰려고 한적이 있었는데 마침 똑같은 주제의 글이