<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-5528327799371258461</atom:id><lastBuildDate>Mon, 21 May 2012 06:19:42 +0000</lastBuildDate><category>Kent Beck</category><category>exception safety</category><category>c.l.c.m</category><category>cbd</category><category>adl</category><category>news</category><category>encoding</category><category>books</category><category>my wiki</category><category>name-lookup</category><category>boost</category><category>unit-testing</category><category>low-level</category><category>static-analysis</category><category>parsing</category><category>koenig-lookup</category><category>reponsive design</category><category>back-door</category><category>source-code</category><category>CLU</category><category>mpl</category><category>sequence-point</category><category>defensive programming</category><category>software engineering</category><category>unicode</category><category>professional</category><category>ambient findability</category><category>access-check</category><category>busybox</category><category>eclipse</category><category>solaris</category><category>c++</category><category>rss-reader</category><category>reading</category><category>tr1</category><category>뉴욕의 프로그래머</category><category>sbcl</category><category>java</category><category>foreach</category><category>refactoring</category><category>Javascript</category><category>overload-resolution</category><category>vmware</category><category>theme</category><category>core</category><category>freemind</category><category>9.11</category><category>programming by contract</category><category>algorithm</category><category>state</category><category>wordpress</category><category>slime</category><category>visual studio</category><category>multiple-inheritance</category><category>desktop</category><category>command line option</category><category>flickr</category><category>optimization</category><category>robert l. glass</category><category>feedburner</category><category>ubuntu</category><category>blogging</category><category>trackback</category><category>textiler</category><category>abi</category><category>prevent</category><category>ide</category><category>porting</category><category>autoconf</category><category>jazz</category><category>xmlcpp</category><category>codehighlighter</category><category>debugging</category><category>generic</category><category>quote</category><category>Software design</category><category>map</category><category>proprocessor</category><category>flock</category><category>youtube</category><category>coverity</category><category>design pattern</category><category>miscellany</category><category>download</category><category>blub</category><category>me2day</category><category>python</category><category>plugin</category><category>sizeof</category><category>Programming language</category><category>orientation</category><category>bad smell</category><category>mindmap</category><category>teaching</category><category>code review</category><category>thinking</category><category>linux</category><category>assert</category><category>textpattern</category><category>del.icio.us</category><category>ternary-conditional-operator</category><category>comma-operator</category><category>emacs</category><category>access level</category><category>c++ of the day</category><category>code inspection</category><category>vacation</category><category>mkseo</category><category>stream</category><category>programming</category><category>conspiracy</category><category>sqlite</category><category>임백준</category><category>erich-gamma</category><category>lisp</category><category>static-member</category><category>font</category><category>join</category><category>quiz</category><category>signals</category><category>the-c++-source</category><category>paul graham</category><category>checked exception</category><category>tuple</category><category>pimpl</category><category>economics</category><category>nvi</category><category>iterator</category><category>s.f.</category><category>web2.0</category><category>c++98</category><category>pedantic</category><category>pattern</category><category>exception</category><category>IE</category><category>qt</category><category>bookcover</category><category>korean</category><category>visitor</category><title>IdeA thinKING</title><description></description><link>http://www.ideathinking.com/</link><managingEditor>noreply@blogger.com (Wongoo Lee)</managingEditor><generator>Blogger</generator><openSearch:totalResults>130</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-8495900504433695100</guid><pubDate>Wed, 08 Feb 2012 22:13:00 +0000</pubDate><atom:updated>2012-02-08T14:14:15.106-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Javascript</category><category domain='http://www.blogger.com/atom/ns#'>IE</category><title>'undefined' is null or not an object</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;&lt;pre id="TargetResultLogContent" style="background-color: white; line-height: 18px; text-align: -webkit-auto; white-space: pre-wrap;"&gt;아 IE...&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="background-color: white; line-height: 18px; text-align: -webkit-auto; white-space: pre-wrap;"&gt;&lt;pre id="TargetResultLogContent" style="white-space: pre-wrap;"&gt;&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="white-space: pre-wrap;"&gt;'undefined' is null or not an object&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="white-space: pre-wrap;"&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="background-color: white; line-height: 18px; text-align: -webkit-auto; white-space: pre-wrap;"&gt;Javascript 테스트 코드가 위 에러를 내면서 실행되질 않아서 삽질 좀 하다 찾아보니...&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="background-color: white; line-height: 18px; text-align: -webkit-auto; white-space: pre-wrap;"&gt;&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="background-color: white; line-height: 18px; text-align: -webkit-auto; white-space: pre-wrap;"&gt;&lt;a href="http://www.delphifaq.com/faq/javascript/extjs/f3476.shtml" target="_blank"&gt;Look for any array of properties that has a trailing , (comma).&lt;/a&gt;&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="background-color: white; line-height: 18px; text-align: -webkit-auto; white-space: pre-wrap;"&gt;&lt;/pre&gt;&lt;pre id="TargetResultLogContent" style="background-color: white; line-height: 18px; text-align: -webkit-auto; white-space: pre-wrap;"&gt;흑흑...&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-8495900504433695100?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2012/02/undefined-is-null-or-not-object.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-1999819833420771859</guid><pubDate>Tue, 24 Jan 2012 03:56:00 +0000</pubDate><atom:updated>2012-01-23T19:56:41.682-08:00</atom:updated><title>오리지널 레고 마인드스톰 부활 프로젝트</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;아... 이 사이트 너무 놀리는거 같아서 스킨 새 단장하고 글 하나. 참 스킨은 &lt;a href="http://www.plaintxt.org/" target="_blank"&gt;www.plaintxt.org&lt;/a&gt;&amp;nbsp;비슷하게 만들어 봤습니다.&lt;br /&gt;&lt;br /&gt;약 12년전에 산 레고 마인드스톰이 있어서 애들한테 어떻게 굴러가게 만드는지 보여주려고 하니 여러가지가 걸리더군요. 일단 박스에 딸려온 소프트웨어는 Windows7에선 안 돌아가고 집에 있는 랩탑엔 씨리얼포트가 없고... 씨리얼포트... 정말 오랫만에 들어보는군요.&lt;br /&gt;&lt;br /&gt;예전에 한번 써봤던 &lt;a href="http://bricxcc.sourceforge.net/nqc/" target="_blank"&gt;NQC&lt;/a&gt;로 코딩은 하면 될것 같은데 씨리얼포트는 달리 방법이 없어서 일단 아마존에서 &lt;a href="http://www.amazon.com/Plugable-Adapter-Prolific-PL2303HX-Chipset/dp/B00425S1H8/ref=sr_1_6?s=electronics&amp;amp;ie=UTF8&amp;amp;qid=1326692055&amp;amp;sr=1-6" target="_blank"&gt;어댑터&lt;/a&gt;를 하나 구입했습니다. 어댑터 도착 후 테스트해보니 씨리얼포트는 정상적으로 인식하더군요. 감동... ㅜㅜ &amp;nbsp;&lt;a href="http://bricxcc.sourceforge.net/" target="_blank"&gt;Brix Command Center (BCC)&lt;/a&gt;라는 GUI도 있어서 설치해서 사용해보니 한 2%정도 편해지더군요. 이렇게되니 얼마전 쌍둥이들이 잃어버린 터치센서 하나가 무척 아쉬워지네요.&lt;br /&gt;&lt;br /&gt;애들은 레고 시티 시리즈를 주로 가지고 노는데 나중에 자동문이나 회전목마같은거나 만들어줘야겠네요.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-1999819833420771859?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2012/01/blog-post.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-4094724701490827598</guid><pubDate>Fri, 07 Jan 2011 06:06:00 +0000</pubDate><atom:updated>2011-01-06T22:06:40.333-08:00</atom:updated><title>Blogger.com으로 이전했습니다.</title><description>근 1년반만에 쓰는 포스팅인데 블로그 이전 메일이군요. ㅎㅎ&lt;br /&gt;워드프레스 호스팅을 사용하고 있었는데 바꿨습니다. 사용한 방법은&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;워드프레스 관리 페이지에서 export 메뉴로 xml 파일 다운로드&lt;/li&gt;&lt;li&gt;이미지 파일의 링크들을 찾아 피카사 앨범에 업로드 (이미지 파일은 10개 이하라 일일이 손으로 피카사 앨범으로 옮겨주었습니다.)&lt;/li&gt;&lt;li&gt;1번에서 백업했던 xml 파일에서 이미지 파일 링크들을 피카사 링크로 변경&lt;/li&gt;&lt;li&gt;&lt;a href="http://wordpress2blogger.appspot.com/"&gt;http://wordpress2blogger.appspot.com/&lt;/a&gt;&amp;nbsp;를 사용하여 블로거 export 파일로 변경&lt;/li&gt;&lt;li&gt;블로거 관리 페이지에서 import&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;끝.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;이미지 외 일반 파일들은 모두 무시하였습니다. ㅎㅎ&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-4094724701490827598?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2011/01/bloggercom.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-2465822646130904173</guid><pubDate>Mon, 12 Oct 2009 14:52:00 +0000</pubDate><atom:updated>2011-01-05T00:39:05.672-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>c++</category><category domain='http://www.blogger.com/atom/ns#'>Programming language</category><category domain='http://www.blogger.com/atom/ns#'>sizeof</category><title>arraysizeof macro</title><description>다음 macro는 array의 length를 구하는 것인데 해석이 되시나요?&lt;br/&gt;&lt;pre&gt;template &amp;lt;typename T, size_t N&amp;gt;&lt;br/&gt;char (&amp;amp;Helper(T (&amp;amp;array)[N]))[N];&lt;br/&gt;#define arraysize(array) (sizeof(Helper(array)))&lt;/pre&gt;&lt;br/&gt;...&lt;br/&gt;&lt;br/&gt;안되신 분들을 위한 설명입니다. ;)&lt;br/&gt;&lt;br/&gt;위 코드는 다음 두가지 사실만 알고 있다면 (비교적) 쉽게 이해됩니다.&lt;br/&gt;&lt;br/&gt;&lt;strong&gt;sizeof는 function call syntax에 대해서도 동작하며 그 function의 return type에 대해 동작한다.&lt;/strong&gt;&lt;br/&gt;&lt;pre&gt;int foo() { return int(); }&lt;br/&gt;...&lt;br/&gt;sizeof(foo()) == sizeof(int)&lt;/pre&gt;&lt;br/&gt;&lt;strong&gt;array type의 reference를 리턴하는 method의 signature는 다음과 같다.&lt;/strong&gt;&lt;br/&gt;&lt;pre&gt;char (&amp;amp;bar)[10]() { ... }&lt;/pre&gt;&lt;br/&gt;이를 바탕으로 arraysizeof를 만들려면 char(&amp;amp;)[N]을 리턴하는 method를 만들면 되죠. 여기서 N은 array의 length.&lt;br/&gt;&lt;pre&gt;template &amp;lt;typename T, size_t N&amp;gt;&lt;br/&gt;char (&amp;amp;Helper(T (&amp;amp;array)[N]))[N] {&lt;br/&gt;...&lt;br/&gt;}&lt;/pre&gt;&lt;br/&gt;위 함수는 T(&amp;amp;)[N]을 parameter로 받아 char(&amp;amp;)[N]을 리턴합니다. 물론 T(&amp;amp;)[N] parameter는 이 template method의 implicit instantiation이 동작하도록 하기 위해 필요합니다. 마지막으로 sizeof는 method body가 필요없으므로...&lt;br/&gt;&lt;pre&gt;template &amp;lt;typename T, size_t N&amp;gt;&lt;br/&gt;char (&amp;amp;Helper(T (&amp;amp;array)[N]))[N];&lt;/pre&gt;&lt;br/&gt;끝.&lt;br/&gt;&lt;br/&gt;참고로 이런 코드가 필요한 이유는 널리 쓰이는 "sizeof(array) / sizeof(*array)" macro가 다음과 같은 경우 compile error없이 오동작하기 때문입니다.&lt;br/&gt;&lt;pre&gt;void foo(int array[]) {&lt;br/&gt;  int size = sizeof(array);&lt;br/&gt;}&lt;/pre&gt;&lt;br/&gt;이 코드에서 array는 pointer와 같이 취급되어 sizeof(array)는 sizeof(int*)가 됩니다.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-2465822646130904173?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2009/10/arraysizeof-macro.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-1431858536139286477</guid><pubDate>Fri, 25 Sep 2009 11:45:00 +0000</pubDate><atom:updated>2011-01-16T14:08:11.655-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Programming language</category><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>generic</category><title>Java generic in return context</title><description>아래 코드를 보시고 1, 2번 라인중에 어디서 에러가 날 지를 찾아보세요.&lt;br /&gt;&lt;pre&gt;interface B {&lt;br /&gt;void doB();&lt;br /&gt;}&lt;br /&gt;class D implements B {&lt;br /&gt;public void doB() {}&lt;br /&gt;}&lt;br /&gt;interface H {&lt;br /&gt;B getB();&lt;br /&gt;}&lt;br /&gt;class HImpl implements H {&lt;br /&gt;public B getB() {&lt;br /&gt;return new D();  // 1)&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;H h = new HImpl();&lt;br /&gt;D d = h.getB(); // 2)&lt;/pre&gt;&lt;br /&gt;네, 2번 라인입니다.&lt;br /&gt;&lt;br /&gt;그럼 다음 코드는?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;interface B1 {&lt;br /&gt;void doB1();&lt;br /&gt;}&lt;br /&gt;interface B2 {&lt;br /&gt;void doB2();&lt;br /&gt;}&lt;br /&gt;class D implements B1, B2 {&lt;br /&gt;public void doB1() {}&lt;br /&gt;public void doB2() {}&lt;br /&gt;}&lt;br /&gt;interface H {&lt;br /&gt;&amp;lt;T extends B1 &amp;amp; B2&amp;gt; T getB();&lt;br /&gt;}&lt;br /&gt;class HImpl implements H {&lt;br /&gt;public &amp;lt;T extends B1 &amp;amp; B2&amp;gt; T getB() {&lt;br /&gt;return new D();  // 1)&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;H h = new HImpl();&lt;br /&gt;D d = h.getB(); // 2)&lt;/pre&gt;&lt;br /&gt;네, 1번입니다. 잘 이해가 되질 않아 사내 메일링 리스트에 물어보니&lt;br /&gt;&lt;blockquote&gt;I think you're seeing  and interpreting it as "this method can return anything that implements both interfaces".  What it's actually saying is &lt;strong&gt;"the caller is going to tell you a specific class that implements both interfaces, and you must return one of those"&lt;/strong&gt;.&lt;/blockquote&gt;&lt;br /&gt;이랍니다. 즉 T 타입이 아직 결정되지 않은 상태라 D와 T는 compatible한 타입이 아닌거죠.&lt;br /&gt;&lt;br /&gt;강제로 casting을 해서 컴파일이 되게 만들면 그 코드는 runtime error (ClassCastException)를 발생하게 됩니다. 다음 코드를 보세요. 즉 이런 방법으론 도저히 type-safe한 코드를 작성할 수 없습니다.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class D2 implements B1, B2 {&lt;br /&gt;public void doB1() {}&lt;br /&gt;public void doB2() {}&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;D2 d = h.getB(); // ClassCastException!!&lt;/pre&gt;&lt;br /&gt;이 같은 상황을 방지하기 위해 1번 라인에서 에러를 내 주는 것이죠.&lt;br /&gt;&lt;br /&gt;코딩 가이드라인을 만들어 보자면 &lt;strong&gt;"method의 parameter로 사용되지 않는 type variable을 사용하면 안된다"&lt;/strong&gt;입니다. 다음과 같은 경우는 parameter로도 사용되고 있으므로 문제가 &amp;nbsp;없는 경우들입니다.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;T&amp;gt; T makeInstance(Class&amp;lt;T&amp;gt; cls) { return cls.newInstance(); }&lt;br /&gt;...&lt;br /&gt;&amp;lt;T extends Comparable&amp;lt;? super T&amp;gt;&amp;gt; T min(T a, T b) {&lt;br /&gt;return a.compareTo(b) &amp;lt; 1 ? a : b;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;위의 예제 코드같은 경우 아래와 같은 방법으로 type-safe하게 작성될 수 있습니다.  &lt;br /&gt;&lt;pre&gt;interface B1 {&lt;br /&gt;void doB1();&lt;br /&gt;}&lt;br /&gt;interface B2 {&lt;br /&gt;void doB2();&lt;br /&gt;}&lt;br /&gt;class D implements B1, B2 {&lt;br /&gt;public void doB1() {}&lt;br /&gt;public void doB2() {}&lt;br /&gt;}&lt;br /&gt;interface H  &amp;lt;T extends B1, B2&amp;gt; {&lt;br /&gt;T getB();&lt;br /&gt;}&lt;br /&gt;class HImpl implements H&amp;lt;D&amp;gt; {&lt;br /&gt;public D getB() {&lt;br /&gt;return new D();  // 1)&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;H&amp;lt;D&amp;gt; h = new HImpl();&lt;br /&gt;D d = h.getB(); // 2)&lt;/pre&gt;&lt;br /&gt;사실... 아직도 잘 모르겠어요. Java generic. =(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-1431858536139286477?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2009/09/java-generic-in-return-context.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>7</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-4936432045950684307</guid><pubDate>Tue, 22 Sep 2009 07:12:00 +0000</pubDate><atom:updated>2011-01-05T00:39:05.414-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Programming language</category><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>access level</category><title>Access level of methods in package-private class</title><description>Java에서 (C++도 마찬가지지만) 권장되는 access level 사용법은 다음과 같습니다.&lt;br/&gt;&lt;blockquote&gt;Use &lt;strong&gt;the most restrictive access level&lt;/strong&gt; that makes sense for a particular member.&lt;/blockquote&gt;&lt;br/&gt;쉽게 얘기해서 private으로 충분하면 private을 쓰고 다음으로 package-private, protected, public 순으로 쓰라는 얘기.&lt;br/&gt;&lt;br/&gt;그런데 C++와는 달리 Java는 class에도 public과 package-private 두 종류의 access level이 있습니다. 이 중 public class의 method들은 위의 권장 사항을 따르면 될 듯 한데 package-private class일 경우는 어떨까요?&lt;br/&gt;&lt;br/&gt;Package-private class에서는 실제 사용될 수 있는 조건으로 봤을 때 method들이 public이건 protected건 모두 package-private과 같은 조건을 가집니다. 즉, 아무리 method의 access level을 public이나 protected로 해봐야 다른 package에선 이 method를 사용할 수가 없습니다. 따라서 the most restrictive한 level을 사용하라는 위 권장 사항을 따르자면 package-private class의 method들은private이 아니라면 모두 package-private access level을 사용해야 합니다.&lt;br/&gt;&lt;br/&gt;그런데 코딩을 하다보니 이 방법엔 한가지 문제가 있더군요. 가끔 package-private class를 public class로 만들어야 할 경우들이 생기는데 이때 method들이 모두 package-private이면 다른 package에서 사용할 수가 없습니다. 그래서 다시 method들의 access level을 조정해야 할 필요가 생기는데 이 시점은 이미 코드를 작성했을 때와 멀어서 자칫 잘못된 access level을 지정할 수 있게 됩니다.&lt;br/&gt;&lt;br/&gt;그래서 생각한건데... package-private class의 method들을 만들 때 access level은 이 class의 access level을 public으로 가정하고 작성하는 것이 어떨까요?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-4936432045950684307?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2009/09/access-level-of-methods-in-package.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-1086881706101026292</guid><pubDate>Wed, 16 Sep 2009 10:58:00 +0000</pubDate><atom:updated>2011-01-09T17:58:58.532-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>CLU</category><category domain='http://www.blogger.com/atom/ns#'>Software design</category><title>A History of CLU</title><description>&lt;a href="http://ideathinking.com/blog-v3/?p=61"&gt;Checked exception&lt;/a&gt; 관련 글들을 찾아 보다가 읽게 된 문서입니다. CLU라는 프로그래밍 언어를 개발하게 된 배경과 과정에 대한 내용인데 정말 재밌네요. 참고로 문서가 좀 길어보이지만 한 1/3은 부록입니다. :)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.lcs.mit.edu/publications/pubs/pdf/MIT-LCS-TR-561.pdf"&gt;A History of CLU&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;거의 30~40년전 이야기인데 현재 사용하고 있는 언어들이 여기서 앞으로 많이 나간것 같아 보이지 않네요.&lt;br /&gt;&lt;blockquote&gt;As mentioned, the concept of data abstraction arose &lt;strong&gt;out of work on structured programming and&amp;nbsp;modularity&lt;/strong&gt; that was aimed at a new way of organizing programs.&amp;nbsp;The resulting programming methodology is &lt;strong&gt;object-oriented&lt;/strong&gt;.&lt;/blockquote&gt;&lt;blockquote&gt;A keystone of the methodology is its focus on &lt;strong&gt;independence of modules&lt;/strong&gt;.&lt;/blockquote&gt;&lt;blockquote&gt;Achieving independence requires two things: &lt;strong&gt;encapsulation and specification&lt;/strong&gt;.&lt;/blockquote&gt;&lt;blockquote&gt;&lt;strong&gt;Specifications are needed to describe what the module is supposed to do in an implementation-independent way&lt;/strong&gt; so that many different implementations are allowed. (&lt;strong&gt;Code is not a satisfactory&amp;nbsp;description since it doesn’t distinguish what is required from ways of achieving it&lt;/strong&gt;. One of the striking&amp;nbsp;aspects of much of the work on object-oriented programming has been &lt;strong&gt;its lack of understanding of the&amp;nbsp;importance of specifications&lt;/strong&gt;; instead the code is taken as the definition of behavior.)&lt;/blockquote&gt;&lt;blockquote&gt;Specifications also allow code that uses the abstraction to be written before&amp;nbsp;code that implements the abstraction, and therefore&lt;strong&gt; are necessary if you want to do top-down&amp;nbsp;implementation&lt;/strong&gt;.&lt;/blockquote&gt;&lt;blockquote&gt;In essence, having a language enforce encapsulation means that &lt;strong&gt;the compiler proves a&amp;nbsp;global property&lt;/strong&gt; of a program; given this proof, &lt;strong&gt;the rest of the reasoning can be localized&lt;/strong&gt;.&lt;/blockquote&gt;&lt;blockquote&gt;CLU favors program readability and understandability over ease&amp;nbsp;of writing, since we believed that these were more important for our intended users.&lt;/blockquote&gt;&lt;blockquote&gt;We worked on the implementation in parallel with the design. &lt;strong&gt;We did not allow the implementation to&amp;nbsp;define the language&lt;/strong&gt;, however.&lt;/blockquote&gt;&lt;br /&gt;이 글을 읽고나니&amp;nbsp;Kent Beck이 &lt;a href="http://ideathinking.com/blog-v3/?p=34"&gt;세미나&lt;/a&gt;에서 언급했던 &lt;a href="http://www.amazon.com/gp/product/0138544719/ref=s9_simz_gw_s0_p14_i1?pf_rd_m=ATVPDKIKX0DER&amp;amp;pf_rd_s=center-2&amp;amp;pf_rd_r=0R5VBBHVXY4FK7CA5RQ7&amp;amp;pf_rd_t=101&amp;amp;pf_rd_p=470938631&amp;amp;pf_rd_i=507846"&gt;Structured Design&lt;/a&gt;이라는 책이 읽고 싶어지네요. Kent Beck도 이 책을 언급하며 수십년전에 쓰여진 책인데 필요한 내용이 전부 있다... 뭐 이렇게 소개했었던 것 같은데...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-1086881706101026292?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2009/09/history-of-clu.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-7469544240784409455</guid><pubDate>Tue, 15 Sep 2009 08:47:00 +0000</pubDate><atom:updated>2011-01-16T14:09:15.199-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Software design</category><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>exception safety</category><category domain='http://www.blogger.com/atom/ns#'>mkseo</category><category domain='http://www.blogger.com/atom/ns#'>checked exception</category><title>Checked exception, 이거 써도 되나?</title><description>&lt;a href="http://mkseo.pe.kr/blog/?p=1970"&gt;mkseo님 블로그&lt;/a&gt;에 &lt;a href="http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html"&gt;Best Practices for Exception Handling&lt;/a&gt;에 관한 글이 올라왔는데 댓글을 읽고 쓰고 하다 궁금한게 생겼습니다.&lt;br /&gt;&lt;blockquote&gt;Checked exception, 이거 써도 되나?&lt;/blockquote&gt;mkseo님이 링크를 걸어준&amp;nbsp;&lt;a href="http://www.artima.com/intv/handcuffs.html"&gt;The Trouble with Checked Exceptions&lt;/a&gt;과 &lt;a href="http://www.mindview.net/Etc/Discussions/CheckedExceptions"&gt;Does Java need Checked Exceptions?&lt;/a&gt;, &lt;a href="http://radio.weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html"&gt;Java's checked exceptions were a mistake (and here's what I would like to do about it)&lt;/a&gt;등의 글을 읽다 보니 현재까지의 결론은 "java의 checked exception실험은 실패다"정도인 것 같더군요.&lt;br /&gt;&lt;br /&gt;몇가지 이유로는 &lt;br /&gt;&lt;ol&gt;&lt;li&gt;원래 language designer의 의도와는 달리 많은 exception이 무시되고 있다. 원래 의도는 compile-time에 에러를 냄으로써 개발자들에게 이 예외를 지금 처리하거나 아니면 위로 전달해야 한다는 메시지를 보내는 것이었다. 하지만 예외를 전달하기 위해서는 method의 signature를 수정해야 한다. 개발자들로서는 이 상황을 벗어날 수 있는 가장 쉬운 방법을 찾게 되고, 이게 바로 catch 후 무시하는 것인데 대부분의 코드가 이런 식으로 작성되고 있다. catch (...) {}&lt;/li&gt;&lt;li&gt;원래 exception의 목적중 하나는 예외가 발생한 지점과 처리할 지점의 분리이다. 즉 low-level에서 발생했지만 거기서 처리가 불가능한 exception들을 위로 전달하여 처리하게 한다... 인데... checked exception은 그 사이에 있는 모든 코드가 이 exception에 대해 알아야만 하게 강제한다. 즉, 전달되는 과정이 투명하지 않다.&lt;/li&gt;&lt;li&gt;Versionability - 어느 method가 A, B라는 checked exception만을 던진다고 선언되었다면 client code들은 이 예외만을 처리하거나 위로 전달하도록 작성된다. 나중에 이 method의 다음 버전에서 C라는 exception을 던질 필요가 생기면 client와의 contract이 깨지게 된다.&lt;/li&gt;&lt;li&gt;Scalability - A, B, C, D라는 method들이 각각 4개씩의 checked exception을 던지고 U라는 method가 이 것들을 호출하는데 예외들을 처리하지 않는다면 U는 총 16개의 checked exception을 던진다고 선언해야 한다. 상위로 올라갈 수록 선언해야 할 exception의 개수는 기하급수적으로 늘어나게 된다.&lt;/li&gt;&lt;/ol&gt;등이 있습니다. 4번의 경우에는 각 레벨에 맞는 exception을 정의해서 사용하면 해결할 수는 있을 것 같습니다. 즉, A, B, C, D가 던지는 16개의 exception을 U가 던질 때는 자기의 context에 맞는 예외 두어개로 mapping하여 던진다는 식이지요.&lt;br /&gt;&lt;br /&gt;암튼.. 그럼 왜 여지껏 저는 checked exception이 매우 그럴 듯해 보였던 걸까요? C#의 한 language designer가 이렇게 얘기했다네요.&lt;br /&gt;&lt;blockquote&gt;Examination of small programs leads to the conclusion that requiring exception specifications could both enhance developer productivity and enhance code quality, but experience with large software projects suggests a different result -- decreased productivity and little or no increase in code quality.&lt;/blockquote&gt;하지만 몇가지 경우엔 checked exception이 유용할 수 있다고 합니다.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;예외가 significant boundary를 넘어가는 경우. 예를 들어 CORBA의 machine boundary같은... 이런 경우 좀 더 명시적인 예외 스펙이 도움이 된다.&lt;/li&gt;&lt;li&gt;package 내부에서 사용되나 절대 외부로 넘어가서는 안되는 예외의 경우 checked exception을 사용하면 컴파일러가 이를 감시하게 할 수 있다.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;예외에 관해 참고할 만한 글들입니다.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.c2.com/cgi/wiki?ExceptionTunneling"&gt;Exception Tunneling&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.research.att.com/~bs/except.pdf"&gt;Exception Safety: Concepts and Techniques&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.boost.org/community/exception_safety.html"&gt;Lessons Learned from Specifying Exception-Safety for the C++ Standard Library&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-7469544240784409455?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2009/09/checked-exception.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-8430113441114554431</guid><pubDate>Sat, 05 Sep 2009 09:06:00 +0000</pubDate><atom:updated>2011-01-16T14:10:40.382-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Software design</category><category domain='http://www.blogger.com/atom/ns#'>Kent Beck</category><category domain='http://www.blogger.com/atom/ns#'>reponsive design</category><title>Responsive Design seminar - Kent Beck</title><description>&lt;a href="http://agile.egloos.com/5087979"&gt;http://agile.egloos.com/5087979&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;정말 오랫만에 세미나를 가서인지 첫 시간은... 잘 잤다. ㅜㅜ 다음은 기억에 남는 얘기들.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Responsive to&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Constraints&lt;br /&gt;&lt;br /&gt;Feedback from system, people or customers.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step back&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;문제를 만났을 때 한발짝 뒤로 물러서서 바라봐라... 쉬운 예로 어떤 코드의 테스트를 작성하는데 구현하기가 너무 어렵다면 한발짝 뒤로 물러서서 애초에 코드의 설계가 잘못된건 아닌지 확인해봐야 한다. 켄트벡이 든 예는 회전문이었는데... 회전문의 &amp;nbsp;throughput, latency, variance등의 조건을 모두 고려하여 설계하기는 불가능하다. 이때 한발짝 물러서서 왜 회전문이 개선되어야 하는지, 혹시 문밖에 있는 인기있는 커피점때문은 아닌지 보자... 만약 그렇다면 커피점을 문안으로 들여오자. 뭐 이런 얘기...&lt;br /&gt;&lt;br /&gt;마침 같이 갔던 H씨가 코드가 바뀔때마다 깨지는 테스트때문에 고민하고 있었는데 한발짝 물러서서 꼭 테스트가 필요한지 확인해보고 지워버리라고 조언... ㅎㅎ&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Retrospect&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;자신이 하는 일을 돌아보자. 왜 이렇게 했는지...&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Goal&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Steady flow of features.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Design - beneficially relating elements&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;설계란 element들간의 관계인데 서로에게 이롭게 만드는 것.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Ambiguity&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;최선의 설계가 무엇인지 모호할 때는 그대로 놔두는 것도 필요. 그대로 놔두면 코드는 점점 망가지며 스스로 해결책을 드러낼 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Safe steps&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;위험하며 효율적인(빠른) 방법보다는 안전하며 덜 효율적인 방법을 선호. 물론 안전하며 덜 효율적인 방법을 빨리 사용할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Values&lt;/strong&gt;&lt;br /&gt;아직 명확하진 않지만... 예를 들면 simplicity, feedback, community&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Patterns&lt;/strong&gt;&lt;br /&gt;대부분의 디자인 결정은 problem domain과 관계가 없고 실제론 컴퓨터에게 시키는 instruction들에 의해 결정되고, 같은 패턴들이 반복되더라.&lt;br /&gt;&lt;br /&gt;시간 낭비를 방지한다.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Principles&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Strategies&lt;/strong&gt;&lt;br /&gt;Can see? (a design what you want)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Leap - 한번에 구현. 위험하나 효율적&lt;/li&gt;&lt;li&gt;Parallel - 동시에 이전 설계와 새 설계를 지원하여 서서히 이전&lt;/li&gt;&lt;/ul&gt;Can't see?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Stepping stone - 이런게 있으면 설계가 쉬워지겠다고 생각하는 항목을 구현 (framework?)&lt;/li&gt;&lt;li&gt;Simplification - 문제의 쉬운 버전을 일단 설계하고 얻은 경험을 바탕으로 서서히 원래 문제를 해결&lt;/li&gt;&lt;/ul&gt;Or&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Add it anyway&lt;/li&gt;&lt;li&gt;Expect to pay the price later - 나중에 문제가 커지면 스스로 해결책을 드러낼 수도...&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;Coupling and cohesion&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Coupling - 어떤 element 변경시 다른 element들이 변경될 확률. Hidden coupling은 발견하기가 매우 어렵다.&lt;/li&gt;&lt;li&gt;Cohesion - 어떤 sub-element 변경시 다른 sub-element들이 변경될 확률. Coupling보다 추적이 용이하다.&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;Refactoring&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Bi-directional&lt;/li&gt;&lt;li&gt;Isolate change (Coupling and cohesion) - Cohesion이 높은 element로 extract한 후 변경&lt;/li&gt;&lt;li&gt;Interface or implementation - 동시에 interface와 implementation을 변경하지 않는다.&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;Succession&lt;/strong&gt;&lt;br /&gt;Succession of vegetative communities.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Data&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Design is an island&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No "best" design - 최선의 디자인은 없다.&lt;/li&gt;&lt;li&gt;Improvement&lt;/li&gt;&lt;li&gt;Deterioration&lt;/li&gt;&lt;li&gt;Sea level&lt;/li&gt;&lt;li&gt;Change in basis&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;Observations&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Power laws&lt;/li&gt;&lt;li&gt;Fractal - 같은 패턴이 여러 규모의 구조에서 발견된다.&lt;/li&gt;&lt;li&gt;Symmetry - 예를 들어 4개의 member field들 중 하나만 다른 행동을 한다면 그 클래스에 속하지 않는 녀석이 아닐까?&lt;/li&gt;&lt;li&gt;Punctuated&amp;nbsp;equilibrium&lt;/li&gt;&lt;/ul&gt;이외에 설계시 social 입장을 고려해야 한다는 얘기도 있었다. 좋은 설계이나 팀원들이 이해할 수 없거나 아직 받아들이기 힘든 경우도 고려해야 한다는 얘기였던 듯...&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;추가&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.infoq.com/presentations/responsive-design"&gt;http://www.infoq.com/presentations/responsive-design&lt;/a&gt;에서 거의 같은 내용을 볼 수 있네요.&lt;br /&gt;&lt;br /&gt;발표 자료는 &lt;a href="http://agile.egloos.com/5106266"&gt;http://agile.egloos.com/5106266&lt;/a&gt;에 있습니다.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-8430113441114554431?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2009/09/responsive-design-seminar-kent-beck.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>5</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-444877340737713141</guid><pubDate>Wed, 10 Oct 2007 23:54:00 +0000</pubDate><atom:updated>2011-01-05T00:33:03.506-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>busybox</category><category domain='http://www.blogger.com/atom/ns#'>linux</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><title>argv[0]</title><description>main 함수의 인자인 argv 배열의 첫번째 항목에는 command line에서 입력된 첫번째 인자, 즉 수행되는 프로그램의 이름이 들어갑니다. ((int main(int argc, char* argv[]) )) 일반적으로 이 argv[0]는 잘 사용하지 않지요. 간혹 usage 출력에 사용되기는 합니다만...&lt;br/&gt;&lt;br/&gt;그런데 예전에 Embedded Linux 교육을 받으면서 보니 이 argv[0] 항목을 사용한 &lt;a href="http://en.wikipedia.org/wiki/Busybox"&gt;BusyBox&lt;/a&gt;라는 재밌는 프로젝트가 있더군요.&lt;br/&gt;&lt;br/&gt;Embedded 시스템들은 일반 시스템들보다 컴퓨팅 파워나 메모리 용량, 디스크 크기(플래시 메모리)에 있어서 제약이 많습니다. 그리고 하나의 a.out에는 그 프로그램이 실행해야 할 내용외에도 수 kb의 내용이 오버헤드로 포함됩니다. 이 오버헤드를 줄이게 되면 좀 더 작은 디스크나 플래시 메모리를 사용할 수 있게 되죠.&lt;br/&gt;&lt;br/&gt;이 오버헤드를 줄이기 위해서 하나의 a.out에 다양한 프로그램의 기능을 집어넣은 것이 BusyBox입니다. 이렇게 만들어진 busybox라는 a.out은 다양한 이름으로 link가 됩니다. 제가 교육받으면서 만들었던 시스템의 /usr/bin 디렉토리에서 ls -l 한 결과를 예로 보면 다음과 같습니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="sh"&gt;&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 [ -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 ar -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 awk -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 basename -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 bunzip2 -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 bzcat -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507             3 Mar 28  2007 captoinfo -&gt; tic&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 chvt -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 clear -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 cmp -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 cut -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 dc -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 deallocvt -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 dirname -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 du -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 env -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 expr -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 find -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 free -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 ftpget -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 ftpput -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 head -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 hexdump -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 id -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507             3 Mar 28  2007 infotocap -&gt; tic&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 install -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 killall -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 last -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 loadfont -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 logger -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 logname -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 md5sum -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 mesg -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 mkfifo -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 nc -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 nslookup -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 od -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 openvt -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 passwd -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 printf -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 readlink -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 renice -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 reset -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 seq -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 setkeycodes -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 sort -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 strings -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 tail -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 tee -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 telnet -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 test -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 tftp -&gt; ../../bin/busybox&lt;br/&gt;-rw-r--r--    1 root     root            0 Feb 28  2007 tic&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 time -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 top -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 tr -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 traceroute -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 tty -&gt; ../../bin/busybox&lt;br/&gt;-rwxr-xr-x    1 507      507        234861 Feb 28  2007 udevinfo&lt;br/&gt;-rwxr-xr-x    1 507      507        358008 Feb 28  2007 udevtest&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 uniq -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 unzip -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 uptime -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 uudecode -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 vlock -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 wc -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 wget -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 which -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 who -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 whoami -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 xargs -&gt; ../../bin/busybox&lt;br/&gt;lrwxrwxrwx    1 507      507            17 Mar 28  2007 yes -&gt; ../../bin/busybox&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;그리고 구현 방법을 보면... 실제 코드는 조금 다르지만 원리는 간단히 argv[0]를 사용하는 것이죠.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;...&lt;br/&gt;else if (strcmp("ls", argv[0]) == 0) do_ls();&lt;br/&gt;else if (strcmp("telnet", argv[0]) == 0) do_telnet();&lt;br/&gt;...&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;아이디어 좋죠? :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-444877340737713141?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/10/argv0.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>4</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-8158788954048374636</guid><pubDate>Tue, 09 Oct 2007 23:07:00 +0000</pubDate><atom:updated>2011-01-05T00:33:03.435-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>thinking</category><category domain='http://www.blogger.com/atom/ns#'>quote</category><category domain='http://www.blogger.com/atom/ns#'>임백준</category><category domain='http://www.blogger.com/atom/ns#'>뉴욕의 프로그래머</category><category domain='http://www.blogger.com/atom/ns#'>reading</category><title>뉴욕의 프로그래머</title><description>뉴욕의 프로그래머라는 책을 읽었습니다. 이미 개발자들을 위한 재밌는 책들을 몇 권 쓰신 임백준씨의 책인데 기대보다는 좀... 장르가 애매해서일까요? 그래도 이런 책이 나왔다는 것 자체가 일단 좋은 일이라고 생각합니다. :-)&lt;br/&gt;&lt;br/&gt;각 장의 처음에는 몇 개의 말들이 인용되고 있는데 그 중에서 다음 것들에 대해 생각해 보았습니다.&lt;br/&gt;&lt;br/&gt;&lt;blockquote&gt;좋은 판단은 경험에서 나온다. 그리고 경험은 나쁜 판단에서 나온다. - 배리 르패트너&lt;br/&gt;&lt;br/&gt;컴퓨터 사이언스를 가르치는 교육이 어떤 사람을 전문적인 프로그래머로 만들지 못하는 것은 붓질과 채색 방법을 가르치는 교육이 어떤 사람을 전문적인 화가로 만들지 못하는 것과 같다. - 에릭 레이먼드&lt;/blockquote&gt;&lt;br/&gt;&lt;br/&gt;첫번째 말에 따르면 좋은 판단, 그리고 그것보다 더 좋은 판단을 하기 위해서는 나쁜 판단을 계속 저질러봐야 한다는 얘기가 됩니다. 결국 모르는 것을 부끄러워하지 않고 지속적으로 배우고 공부해야 한다는 얘기인데... 말처럼 쉽지 않은 것 같습니다. 특히 부끄러워하지 않는 것이요. :-P&lt;br/&gt;&lt;br/&gt;두번째 말은 다른 곳에서도 많이 들었던 것인데 책에서 읽고 이런 생각을 했습니다. 왜 붓질과 채색 방법을 가르치는 교육만 받은 사람은 전문적인 화가가 될 수 없는데 전자의 경우에는 전문적인 프로그래머가 될 수 있을까? ((물론 요새는 프로그래머라는 직업에 대한 인기가 별로 없어 진짜 어설프게 배운 프로그래머의 신규 유입은 거의 없어지지 않았나 싶습니다.))&lt;br/&gt;&lt;br/&gt;제가 생각한 차이점은 붓질과 채색 방법만을 배운 화가의 그림은 진짜 화가의 그림과 쉽게 수준이 비교가 되지만 컴퓨터 사이언스를 배운 프로그래머가 만든 프로그램은 전문가가 만든 것과 쉽게 비교가 되지 않는다는 점입니다. 물론 사용하면서 발생하는 문제들과 문제가 처리되는 방법, 유지보수 용이성등과 같이 세부적인 항목들을 꼼꼼히 검사하면 전문가가 만든것과 확연히 구분되겠지만 일단 기능이 동작하느냐는 관점에서 보면 큰 차이가 나지 않을 수 있죠. ((&lt;a href="http://ideathinking.com/blog-v2/?p=22#comment-26"&gt;이 댓글&lt;/a&gt;과 비슷한 내용입니다.))&lt;br/&gt;&lt;br/&gt;더 큰 문제는 전문 화가의 경우에는 옆에 있는 무늬만 화가가 저질러 놓은 채색과 붓질을 신경쓸 필요가 없지만 프로그래머는 그럴 필요가 있다는 점, 게다가 이런 수정들이 훨씬 더 스트레스를 많이 준다는 점이죠.&lt;br/&gt;&lt;br/&gt;.&lt;br/&gt;.&lt;br/&gt;&lt;br/&gt;책에 나온 말들 중 가장 재밌었던 말은 따로 있습니다. 리치 쿡이란 분... 많이 당하셨나봐요.&lt;br/&gt;&lt;br/&gt;&lt;blockquote&gt;오늘날의 프로그래밍은 소프트웨어 엔지니어와 우주가 경쟁을 벌이는 양상으로 진행되고 있다. 소프트웨어 엔지니어는 바보조차 쉽게 사용할 수 있는 프로그램을 만들기 위해 노력하고, 우주는 바보를 만들어낸다. 적어도 지금까지는 우주가 승리를 거두고 있다. - 리치 쿡&lt;/blockquote&gt;&lt;br/&gt;&lt;br/&gt;여기서의 문제는 윗글에 나오는 바보들이 소프트웨어 엔지니어보다 위에 있다는 점이겠죠? :-)&lt;br/&gt;&lt;br/&gt;아... 그리고 책이 제 기대보다 못 했다고 해서 재미가 없었다는 얘긴 아닌거 아시죠? ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-8158788954048374636?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/10/blog-post.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-1867284298903134278</guid><pubDate>Fri, 28 Sep 2007 11:39:00 +0000</pubDate><atom:updated>2011-01-05T00:33:03.243-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>thinking</category><title>6년 9개월</title><description>오늘이 6년 9개월동안 다녔던 회사에 출근하는 마지막 날입니다. 이제 이 자리에서 블로그에 글 쓰는 건 마지막이군요. 생각해보면 그렇게 길게 느껴졌던 국민학교 6년보다 여기서 더 오래 생활했네요.&lt;br/&gt;&lt;br/&gt;일주일 쉬었다가 다음 회사로 출근합니다.&lt;br/&gt;&lt;br/&gt;왠지 섭섭한 마음에 PC 반납하기 전에 한 줄 적어봤습니다. :-(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-1867284298903134278?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/09/6-9.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-5588066129706614396</guid><pubDate>Thu, 27 Sep 2007 15:04:00 +0000</pubDate><atom:updated>2011-01-17T17:20:36.459-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>c++</category><category domain='http://www.blogger.com/atom/ns#'>sqlite</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>c++ of the day</category><title>C++ of the Day #45 - SQLite3 C++ wrapper #3</title><description>이번엔 sqlite3++를 소개하는 마지막 시간으로 SQLite3의 extension 기능에 대한 부분을 살펴 보겠습니다.&lt;br /&gt;&lt;br /&gt;SQLite3는 사용자가 정의할 수 있는 function과 aggregate들을 통해 기본 기능을 확장할 수 있도록 하고 있습니다. ((이외에 collation sequence라는 확장 기능도 있습니다만 sqlite3++에서는 지원하지 않습니다. 아직까지는...))&lt;br /&gt;&lt;br /&gt;예를 들어 A라는 column의 정보를 가지고 B와 C의 데이터 중 선택할 수 있는 cond(A, B, C)라는 function을 사용자가 정의할 수 있다면 복잡한 SQL 구문 대신 다음과 같이 간단하게 사용할 수 있을 것입니다.&lt;br /&gt;&lt;br /&gt;&lt;pre lang="sql"&gt;SELECT cond(A, B, C) FROM ...;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;그리고 특정 규칙을 적용한 filter를 사용하여 해당 filter에 의해 선택된 항목들의 개수만 세고 싶다면 다음과 같은 aggregate를 만들어 사용할 수도 있습니다. 아래 코드에서는 count_of가 사용자가 정의한 filter라고 가정합니다.&lt;br /&gt;&lt;br /&gt;&lt;pre lang="sql"&gt;SELECT count_of(A, B, C) FROM ...;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;이처럼 function이나 aggregate는 SQLite3가 기본적으로 제공하지 않거나 SQL만으로 작성하기에는 복잡한 기능들을 사용자가 정의할 수 있도록 해줍니다.&lt;br /&gt;&lt;br /&gt;그럼 sqlite3++을 사용하여 간단하게 이런 function이나 aggregate를 만들 수 있는 방법을 알아보겠습니다.&lt;br /&gt;&lt;br /&gt;먼저 ext::function의 경우에는 function pointer나 functor, boost::binder 그리고 boost::lambda등을 function으로 등록하여 사용할 수 있습니다. 예를 들면 다음과 같습니다.&lt;br /&gt;&lt;br /&gt;&lt;pre lang="cpp"&gt;int plus100(int val) {&lt;br /&gt;return val + 100;&lt;br /&gt;}&lt;br /&gt;// ...&lt;br /&gt;sqlite3pp::ext::function func(db);&lt;br /&gt;func.create&lt;int ()=""&gt;("plus100", &amp;amp;plus100);&lt;br /&gt;&lt;br /&gt;// SELECT plus100(id) FROM ...;&lt;br /&gt;&lt;/int&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;위의 plus100()은 단순히 입력된 값에 100이라는 값을 더하여 리턴하는 함수입니다. 등록은 ext::function 객체의 create 함수를 사용하며 template 인자의 문법은 boost::function과 유사하게 &lt;em&gt;function type&lt;/em&gt;이 사용됩니다. :-)&lt;br /&gt;&lt;br /&gt;이처럼 간단한 코드는 boost::lambda로도 등록하여 사용할 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;pre lang="cpp"&gt;using namespace boost::lambda;&lt;br /&gt;func.create&lt;int ()=""&gt;("plus100", _1 + 100);&lt;br /&gt;&lt;/int&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;물론 다음과 같이 입력과 출력의 타입은 서로 다를 수 있으며 입력의 개수는 현재 0~5개까지 지원합니다.&lt;br /&gt;&lt;br /&gt;&lt;pre lang="cpp"&gt;int strlen_3(std::string const&amp;amp; s1, std::string const&amp;amp; s2, std::string const&amp;amp; s3)&lt;br /&gt;{&lt;br /&gt;return (s1 + s2 + s3).size();&lt;br /&gt;}&lt;br /&gt;// ...&lt;br /&gt;func.create_function&lt;int (std::string,="" std::string)="" std::string,=""&gt;("strlen_3", &amp;amp;strlen_3);&lt;br /&gt;&lt;br /&gt;// SELECT strlen_3(A, B, C) FROM ...;&lt;br /&gt;&lt;/int&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;위에서 본 코드와 같이 ext::function은 비교적 간단히 사용할 수 있습니다만 ext::aggregate의 경우에는 약간 복잡합니다. ext::aggregate는 하나의 함수가 아니라 해당 입력값을 하나씩 받아들이는 step()함수와 모든 입력이 끝난 뒤에 리턴값을 처리하는 finish()함수로 구성됩니다.&lt;br /&gt;&lt;br /&gt;ext::function보다 복잡하다고는 하지만 실제 사용 방법은 간단하게 step()함수와 finish()함수를 가지는 클래스를 구현하는 것입니다.&lt;br /&gt;&lt;br /&gt;&lt;pre lang="cpp"&gt;struct strlen_all&lt;br /&gt;{&lt;br /&gt;strlen_all() : n_(0) {&lt;br /&gt;}&lt;br /&gt;void step(std::string const&amp;amp; s) {&lt;br /&gt;n_ += s.size();&lt;br /&gt;}&lt;br /&gt;int finish() {&lt;br /&gt;return n_;&lt;br /&gt;}&lt;br /&gt;int n_;&lt;br /&gt;};&lt;br /&gt;// ...&lt;br /&gt;sqlite3pp::ext::aggregate aggr(db);&lt;br /&gt;aggr.create&lt;strlen_all, std::string=""&gt;("strlen_all");&lt;br /&gt;&lt;br /&gt;// SELECT strlen_all(name) FROM table;&lt;br /&gt;&lt;/strlen_all,&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;위의 ext::aggregate는 해당 column에 있는 문자열의 길이의 합을 리턴합니다.&lt;br /&gt;&lt;br /&gt;등록시에 사용되는 create 함수의 template 인자의 구성은 &lt;aggregate_class, ...="" input_type1,=""&gt;가 됩니다. aggregate의 리턴 타입은 자동으로 finish() 함수의 리턴 타입으로 결정됩니다. 여기서도 입력의 개수는 현재 0~5개까지로 구현되어 있습니다.&lt;br /&gt;&lt;br /&gt;이것으로 구현한 sqlite3++의 사용 방법에 대한 설명을 마치겠습니다. 오랫만에 코드에 template을 좀 썼더니 재밌네요. 기회가 되면 sqlite3++에 사용된 template 구현 방법에 대해 설명해 보도록 하겠습니다. :-)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/sqlite3pp/"&gt;sqlite3pp - Google Code&lt;/a&gt;에서 코드들과 간단한 사용 예제들을 보실 수 있습니다.&lt;/aggregate_class,&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-5588066129706614396?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/09/c-of-day-45-sqlite3-c-wrapper-3.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-372470196533515833</guid><pubDate>Thu, 20 Sep 2007 15:52:00 +0000</pubDate><atom:updated>2011-01-05T00:33:03.188-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>c++</category><category domain='http://www.blogger.com/atom/ns#'>sqlite</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>c++ of the day</category><title>C++ of the Day #44 - SQLite3 C++ wrapper #2</title><description>지난 번에 이어 구현중인 SQLite3 C++ wrapper에 대해 살펴보겠습니다. 먼저 이 wrapper의 이름을 sqlite3++로 결정했습니다. 물론 코드안에서와 같이 특수 문자를 사용할 수 없는 경우에는 sqlite3pp라는 이름을 사용합니다.&lt;br/&gt;&lt;br/&gt;지난번 글의 내용에서 변경된 사항들에 대해 먼저 알아보죠.&lt;br/&gt;&lt;br/&gt;먼저 몇몇 클래스와 함수들의 이름을 알기 쉽게 바꾸었습니다. 다음이 바뀐 이름들의 목록입니다.&lt;br/&gt;&lt;br/&gt;&lt;ol&gt;&lt;br/&gt;	&lt;li&gt;connection --&gt; database&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;connection::open --&gt; database::connect&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;connection::close --&gt; database::disconnect&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;command::step --&gt; command::execute&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;command::finalize --&gt; command::finish&lt;/li&gt;&lt;br/&gt;&lt;/ol&gt;&lt;br/&gt;&lt;br/&gt;클래스 상속 관계도 수정이 되었으나 사용자들에게 보이는 변경 사항은 없습니다.&lt;br/&gt;&lt;br/&gt;그리고 command::step() 함수의 성공시에 SQLITE_DONE(101)이 출력되던 것을 다른 함수들과의 일관성을 위해 command::execute() 함수는 SQLITE_OK(0)를 리턴하도록 수정하였습니다. 이제 sqlite3++에서 함수의 성공 여부는 리턴값이 0인지를 확인하면 됩니다.&lt;br/&gt;&lt;br/&gt;다음으로 SQLite3에서 지원하는 busy_handler, commit_hook, rollback_hook, update_hook, authorizer_handler와 같은 callback 함수들을 등록하는 인터페이스를 database 클래스에 추가하였습니다. 사용하는 방법은 다음과 같이 몇가지가 있습니다. ((boost::function을 사용하여 다양한 타입으로 등록할 수 있도록 구현하였습니다.))&lt;br/&gt;&lt;br/&gt;먼저 일반 함수 포인터를 사용하는 방법입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;int handle_authorize(int evcode, char const* p1, char const* p2, char const* dbname, char const* tvname) {&lt;br/&gt;  cout &lt;&lt; "handle_authorize(" &lt;&lt; evcode &lt;&lt; ")" &lt;&lt; endl;&lt;br/&gt;  return 0;&lt;br/&gt;}&lt;br/&gt;// ...&lt;br/&gt;db.set_authorize_handler(&amp;handle_authorize);&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;이런 callback 함수에 user data가 필요한 경우에는 이를 클래스로 만들어 멤버 함수 포인터를 등록할 수도 있습니다. 아래 코드에서는 boost::bind를 사용하여 멤버 함수 포인터를 전달하고 있습니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;struct handler&lt;br/&gt;{&lt;br/&gt;  handler() : cnt_(0) {}&lt;br/&gt;&lt;br/&gt;  void handle_update(int opcode, char const* dbname, char const* tablename, int64_t rowid) {&lt;br/&gt;    cout &lt;&lt; "handle_update(" &lt;&lt; opcode &lt;&lt; ", " &lt;&lt; dbname &lt;&lt; ", " &lt;&lt; tablename &lt;&lt; ", " &lt;&lt; rowid &lt;&lt; ") - " &lt;&lt; cnt_ &lt;&lt; endl;&lt;br/&gt;    ++cnt_;&lt;br/&gt;  }&lt;br/&gt;  int cnt_;&lt;br/&gt;};&lt;br/&gt;// ...&lt;br/&gt;handler h;&lt;br/&gt;db.set_update_handler(bind(&amp;handler::handle_update, &amp;h, _1, _2, _3, _4));&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;물론 일반 functor를 만들어 사용할 수도 있습니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;struct rollback_handler&lt;br/&gt;{&lt;br/&gt;  void operator()() {&lt;br/&gt;    cout &lt;&lt; "handle_rollback - " &lt;&lt; cnt &lt;&lt; endl;&lt;br/&gt;    ++cnt;&lt;br/&gt;  }&lt;br/&gt;  int cnt;&lt;br/&gt;};&lt;br/&gt;// ...&lt;br/&gt;db.set_rollback_handler(rollback_handler());&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;게다가 위의 경우처럼 함수의 내용이 간단한 경우 boost::lambda를 사용할 수도 있죠. :-)&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;db.set_rollback_handler(cout &lt;&lt; constant("handle_rollback\n"));&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;위의 rollback_handler는 리턴값이 void라 위와 같이 쉽게 사용이 가능하지만 commit_handler와 같이 리턴값이 있는 경우에는 다음과 같이 boost::lambda의 , (comma) operator를 사용하여 리턴값을 지정해 주어야 합니다. 이때는 함수 인자로 인식하지 않도록 괄호를 추가로 사용해야 합니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;db.set_commit_handler((cout &lt;&lt; constant("handle_commit\n"), 0));&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;이 기능외에도 하나의 database 세션에서 다른 db 파일을 연결해서 쓸 수 있는 attach/detach 기능이나 enable_shared_cache() 기능을 위한 인터페이스도 추가되었습니다.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;현재까지 작성된 코드들을 Google Code에 등록해 두었습니다. 다음 링크를 통해 현재 구현중인 코드를 확인할 수 있습니다.&lt;br/&gt;&lt;br/&gt;&lt;a href="http://sqlite3pp.googlecode.com/svn/trunk/"&gt;http://sqlite3pp.googlecode.com/svn/trunk/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;다음 글에서는 sqlite3++의 마지막 시간으로 SQLite3에서 제공하는 extension에 대한 C++ wrapping에 대해 작성해 보도록 하겠습니다. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-372470196533515833?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/09/c-of-day-44-sqlite3-c-wrapper-2.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-8536478033790273813</guid><pubDate>Tue, 18 Sep 2007 14:26:00 +0000</pubDate><atom:updated>2011-08-18T17:50:07.931-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>c++</category><category domain='http://www.blogger.com/atom/ns#'>sqlite</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>c++ of the day</category><title>C++ of the Day #43 - SQLite3 C++ wrapper #1</title><description>&lt;a href="http://www.amazon.com/Definitive-Guide-SQLite/dp/1590596730/ref=pd_bbs_sr_1/103-7142306-3980644?ie=UTF8&amp;s=books&amp;qid=1190077319&amp;sr=8-1"&gt;The Definitive Guide to SQLite&lt;/a&gt;를 읽다가 공부 겸 해서 C++ wrapper를 만들어 보았습니다. 최대한 C++ 냄새(?)가 나도록 만들어 보았습니다. :-) ((SQLite는 복잡한 관리가 필요없이 사용가능한, 파일이나 메모리 기반의, 라이브러리로 제공되는, 약 250kb 용량의, 대부분의 SQL92문을 지원하는, open source RDB입니다.))&lt;br /&gt;이 wrapper를 사용하기 위해서는 (당연하게도!) &lt;a href="http://www.sqlite.org/"&gt;sqlite3&lt;/a&gt;와 (당연하게도?) &lt;a href="http://www.boost.org/"&gt;boost&lt;/a&gt; 라이브러리가 필요합니다.&lt;br /&gt;사용 예들을 살펴보는 것으로 설명을 대신합니다.&lt;br /&gt;이번 글에서는 다음과 같은 contacts 테이블이 test.db에 존재한다고 가정합니다.&lt;br /&gt;&lt;pre lang="sql"&gt;CREATE TABLE contacts&lt;br /&gt;(&lt;br /&gt;id INTEGER PRIMARY KEY,&lt;br /&gt;name TEXT NOT NULL,&lt;br /&gt;phone TEXT NOT NULL,&lt;br /&gt;UNIQUE(name, phone)&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Command&lt;/h2&gt;먼저 test.db 파일을 사용하기 위해 다음과 같이 파일 이름을 주어 connection 객체를 생성합니다. 생성과 동시에 test.db와 연결이 이루어집니다. ((생성자외에 open() 함수를 사용할 수도 있습니다.))&lt;br /&gt;&lt;pre lang="cpp"&gt;sqlite3pp::connection conn("test.db");&lt;br /&gt;&lt;/pre&gt;다음은 contacts 테이블에 정보를 추가하는 가장 간단한 방법입니다. connection 클래스에서 제공하는 execute 함수를 사용합니다. ((executef 함수를 사용하면 printf와 같은 문법을 사용하여 query문을 작성할 수 있습니다.))&lt;br /&gt;&lt;pre lang="cpp"&gt;conn.execute("INSERT INTO contacts (name, phone) VALUES ('user', '1234')");&lt;br /&gt;&lt;/pre&gt;위와 동일한 작업을 parameterized query를 사용하여 할 수도 있습니다. ((step()함수가 실제 query문을 수행하는 함수입니다. run()과 같은 이름을 사용할까 했으나 sqlite에서 사용하는 이름을 그대로 사용하기로 하였습니다.))&lt;br /&gt;&lt;pre lang="cpp"&gt;sqlite3pp::command cmd(conn, "INSERT INTO contacts (name, phone) VALUES (?, ?)");&lt;br /&gt;cmd.bind(1, "user");&lt;br /&gt;cmd.bind(2, "1234");&lt;br /&gt;cmd.step();&lt;br /&gt;// or&lt;br /&gt;sqlite3pp::command cmd(conn, "INSERT INTO contacts (name, phone) VALUES (:name, :phone)");&lt;br /&gt;cmd.bind(":name", "user");&lt;br /&gt;cmd.bind(":phone", "1234");&lt;br /&gt;cmd.step();&lt;br /&gt;&lt;/pre&gt;같은 query문(command 객체)을 재사용하려면 cmd.reset() 함수 호출후에 원하는 필드만 다른 값으로 binding하여 다시 step() 함수를 호출하면 됩니다.&lt;br /&gt;위의 코드 중 두 줄로 된 binding 작업은 다음과 같이 left shift operator를 사용하여 한 줄로 작성이 가능합니다.&lt;br /&gt;&lt;pre lang="cpp"&gt;cmd.binder() &lt;&lt; "user" &lt;&lt; "1234";&lt;br /&gt;&lt;/pre&gt; &lt;h2&gt;Query&lt;/h2&gt;이제 select를 사용하여 데이터를 읽는 방법에 대해서 알아보도록 하겠습니다. 이 경우 command 클래스 대신 query 클래스를 사용합니다. ((query 클래스는 command 클래스를 상속받은 클래스로 record fetch 에 필요한 함수나 클래스, iterator등을 추가로 제공합니다.)) &lt;pre lang="cpp"&gt;sqlite3pp::connection conn("test.db");&lt;br /&gt;&lt;br /&gt;sqlite3pp::query qry(conn, "SELECT id, phone, name FROM contacts");&lt;br /&gt;&lt;/pre&gt;먼저 column name을 가지고 헤더를 출력하려면 다음과 같이 column_name() 함수를 사용합니다. &lt;pre lang="cpp"&gt;for (int i = 0; i &lt; qry.column_count(); ++i) {&lt;br /&gt;cout &lt;&lt; qry.column_name(i) &lt;&lt; "\t";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; 다음으로 한 record씩 읽어오기 위해 query 클래스가 제공하는 iterator를 사용합니다. 각 record에서 column의 값을 읽어오는 방법에는 몇 가지가 있는데 하나씩 살펴보죠. 먼저 각 column의 타입을 모른다면 다음과 같이 무조건 char const* 타입으로 받아 출력하는 방법을 사용할 수 있습니다. ((char const* 타입 대신 std::string 타입을 사용할 수도 있습니다. 하지만 std::string 타입을 사용할 경우 sqlite 내부 버퍼에 있는 text 데이터가 std::string 객체로 복사되는 비용이 추가로 발생합니다.)) &lt;pre lang="cpp"&gt;for (sqlite3pp::query::iterator i = qry.begin(); i != qry.end(); ++i) {&lt;br /&gt;for (int j = 0; j &lt; qry.column_count(); ++j) {&lt;br /&gt;cout &lt;&lt; (*i).get&lt;char const*&gt;(j) &lt;&lt; "\t"; // type conversion is done by sqlite&lt;br /&gt;}&lt;br /&gt;cout &lt;&lt; endl;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; 다음으로 각 column의 타입을 알고 있다면 right shift operator 문법을 사용할 수 있습니다. &lt;pre lang="cpp"&gt;int id;&lt;br /&gt;std::string name, phone;&lt;br /&gt;&lt;br /&gt;for (sqlite3pp::query::iterator i = qry.begin(); i != qry.end(); ++i) {&lt;br /&gt;(*i).getter() &gt;&gt; id &gt;&gt; name &gt;&gt; phone;&lt;br /&gt;cout &lt;&lt; id &lt;&lt; "\t" &lt;&lt; name &lt;&lt; "\t" &lt;&lt; phone &lt;&lt; endl;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; 마지막으로 boost::tuple을 사용하는 방법도 제공합니다. &lt;pre lang="cpp"&gt;for (sqlite3pp::query::iterator i = qry.begin(); i != qry.end(); ++i) {&lt;br /&gt;boost::tie(id, name, phone) =&lt;br /&gt;(*i).get_columns&lt;int, std::string, std::string&gt;(0, 1, 2);&lt;br /&gt;cout &lt;&lt; id &lt;&lt; "\t" &lt;&lt; name &lt;&lt; "\t" &lt;&lt; phone &lt;&lt; endl;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; boost::tuple을 사용하면 원하는 column들을 쉽게 선택할 수 있다는 장점이 있습니다. 예를 들어 위의 코드에서 name과 phone 정보만 필요하다면 다음과 같이 할 수 있습니다. &lt;pre lang="cpp"&gt;boost::tie(name, phone) = (*i).get_columns&lt;std::string, std::string&gt;(1, 2);&lt;br /&gt;// now, int type and 0 index are dropped.&lt;br /&gt;&lt;/pre&gt;물론 right shift operator를 사용하는 방법에도 원하는 column만을 선택할 수 있는 방법이 있습니다. 원하지 않는 column의 자리에 sqlite3pp::ignore를 사용하면 됩니다. &lt;pre lang="cpp"&gt;(*i).getter() &gt;&gt; sqlite3pp::ignore &gt;&gt; name &gt;&gt; phone; // id value is not fetched at all.&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Transaction&lt;/h2&gt;위에 있는 모든 query문들은 autocommit 모드로 동작을 합니다. 한 구문이 한번씩 commit을 사용하는 것이죠. 여러개의 구문을 하나의 transaction으로 묶기 위해서는 transaction 객체를 사용합니다. &lt;pre lang="cpp"&gt;{&lt;br /&gt;sqlite3pp::transaction xct(conn); // begin transaction with default rollback option.&lt;br /&gt;&lt;br /&gt;sqlite3pp::command cmd(conn, "INSERT INTO contacts (name, phone) VALUES (?, ?)");&lt;br /&gt;&lt;br /&gt;cmd.binder() &lt;&lt; "user" &lt;&lt; "1234";&lt;br /&gt;if (SQLITE_DONE != cmd.step())&lt;br /&gt;return; // end transaction with rollback&lt;br /&gt;&lt;br /&gt;cmd.reset(); // reuse cmd object.&lt;br /&gt;&lt;br /&gt;cmd.binder() &lt;&lt; "user" &lt;&lt; "5678";&lt;br /&gt;if (SQLITE_DONE != cmd.step())&lt;br /&gt;return; // end transaction with rollback&lt;br /&gt;&lt;br /&gt;xct.commit(); // end transaction with commit&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; transaction 객체는 RAII를 사용하여 destructor에서 commit 모드에 따라 commit이나 rollback을 하게 됩니다. 물론 명시적으로 commit이나 rollback이 호출된 경우에는 destructor에서 아무 동작도 하지 않습니다. 위의 코드는 기본 모드로 rollback을 사용하고 있으나 다음과 같이 commit을 기본 모드로 설정할 수 있습니다. &lt;pre lang="cpp"&gt;sqlite3pp::transaction xct(conn, true);&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Download&lt;/h2&gt;현재까지 작성한 코드로 위에 나온 내용들은 모두 구현되어 있습니다. &lt;a href="http://ideathinking.com/wiki/images/e/ea/Sqlite3pp.zip"&gt;Sqlite3pp.zip&lt;/a&gt; 앞으로 sqlite3의 extension과 callback 인터페이스들에 대한 C++ wrapping을 추가할 계획입니다. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-8536478033790273813?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/09/c-of-day-43-sqlite3-c-wrapper-1.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-2420124260306825436</guid><pubDate>Wed, 05 Sep 2007 22:45:00 +0000</pubDate><atom:updated>2011-01-05T00:33:02.965-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>web2.0</category><category domain='http://www.blogger.com/atom/ns#'>thinking</category><category domain='http://www.blogger.com/atom/ns#'>ambient findability</category><category domain='http://www.blogger.com/atom/ns#'>reading</category><title>의사 결정의 함정들</title><description>&lt;em&gt;검색2.0 발견의 진화 (Ambient Findability)&lt;/em&gt;라는 책 내용중에서 의사 결정의 함정들이라는 내용입니다. 책의 주제와는 크게 상관없는 연구 결과 내용인데 너무 와 닿습니다.&lt;br/&gt;&lt;br/&gt;&lt;ul&gt;&lt;br/&gt;	&lt;li&gt;&lt;strong&gt;고착&lt;/strong&gt;&lt;br/&gt;결정을 내릴 때 우리의 정신은 우리가 처음 찾아낸 정보의 영향을 많이 받는다. 처음 발견한 데이터와 첫인상에 의해 그 이후의 판단이 고착된다.&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;&lt;strong&gt;확인&lt;/strong&gt;&lt;br/&gt;우리는 무의식적으로 기존의 시각을 옹호하는 데이터를 찾아 선택적으로 검색하고 받아들이며, 그와 반대되는 증거는 피하려고 한다. ((괴짜경제학이라는 책에서도 줄기차게 나왔던 내용이죠.))&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;&lt;strong&gt;각인&lt;/strong&gt;&lt;br/&gt;최근에 있었거나 극적인 사건에 더 영향을 받는다. 어떤 정보가 하나 혹은 여러 개의 출처에서 반복해서 등장할 경우 신념, 기억, 그리고 판단에까지 영향을 미칠 수 있다.&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;&lt;strong&gt;현상 유지&lt;/strong&gt;&lt;br/&gt;의사 결정시 현재 상태를 영속화할 수 있는 보수성, 관성, 대안들에 강하게 치우치는 경향이 있다. 다시 말해 아무 것도 하지 않을 이유를 찾는 것이다.&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;&lt;strong&gt;매몰 비용 (Sunk Cost)&lt;/strong&gt;&lt;br/&gt;의식적이든 아니든, 지나간 실수들을 인정하기 싫어서 과거의 선택을 정당화하는 쪽으로 결정을 내린다.&lt;/li&gt;&lt;br/&gt;&lt;/ul&gt;&lt;br/&gt;&lt;br/&gt;저는 특히 &lt;strong&gt;현상 유지&lt;/strong&gt; 항목의 보수성, 관성등의 말이 무섭게 느껴지더군요. 나도 점점 이렇게 되어 가는건 아닐까 하고요. 언제 어디서든 마음을 열고 이런 함정들에 빠지지 않도록 조심해야겠습니다.&lt;br/&gt;&lt;br/&gt;&lt;blockquote&gt;뛰고 있는데도 힘들지 않다면 그길은 내리막길인 것이다.&lt;/blockquote&gt;&lt;br/&gt;&lt;br/&gt;요새 웹 2.0과 관련된 책들을 찾아 읽고 있는데 그중에서 제일 재밌게 읽었던 책 두권 추천해드립니다. 공교롭게도 둘다 아시아 저자들이네요. (한국, 일본)&lt;br/&gt;&lt;br/&gt;&lt;ol&gt;&lt;br/&gt;	&lt;li&gt;웹 진화론, 우메다 모치오&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;웹 2.0 경제학, 김국현&lt;/li&gt;&lt;br/&gt;&lt;/ol&gt;&lt;br/&gt;&lt;br/&gt;또 괜찮은 책 있으면 추천해주세요. :-) 읽은 책에는 웹 2.0 이노베이션, 검색2.0 발견의 진화, 검색으로 세상을 바꾼 구글 스토리, The Google Story - 구글 성공 신화의 비밀, 웹 2.0 시대의 기회 - 시맨틱 웹 등이 있습니다.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-2420124260306825436?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/09/blog-post.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-1535668536434617041</guid><pubDate>Mon, 27 Aug 2007 14:18:00 +0000</pubDate><atom:updated>2011-01-05T00:33:02.420-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>wordpress</category><category domain='http://www.blogger.com/atom/ns#'>plugin</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>blogging</category><category domain='http://www.blogger.com/atom/ns#'>bookcover</category><title>BookCover plugin test page</title><description>This post is for testing &lt;a href="http://ideathinking.com/wiki/index.php/WordPress:BookCoverPlugin"&gt;BookCover plugin&lt;/a&gt;. ((&lt;a href="http://ideathinking.com/blog/?p=4"&gt;The previous test page&lt;/a&gt; has some comments from users.))&lt;br/&gt;&lt;br/&gt;The 'Books Reading' section in the sidebar is also using this plugin.&lt;br/&gt;&lt;ol&gt;&lt;br/&gt;	&lt;li&gt;[ bookcover:1932394613]&lt;br/&gt;[bookcover:1932394613]&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;[ bookcover:1590598385(Smart and Gets Things Done)]&lt;br/&gt;[bookcover:1590598385(Smart and Gets Things Done)]&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;[ bookcover:1591841380(Wikinomics : How Mass Collaboration Changes Everything)]&lt;br/&gt;[bookcover:1591841380(Wikinomics : How Mass Collaboration Changes Everything)]&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;[ bookcover:8995856408]&lt;br/&gt;[bookcover:8995856408]&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;[ bookcover:8831793721]&lt;br/&gt;[bookcover:8831793721]&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;	&lt;li&gt;[ bookcover:9788831793728]&lt;br/&gt;[bookcover:9788831793728]&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-1535668536434617041?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/08/bookcover-plugin-test-page.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>21</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-8688599884601951648</guid><pubDate>Mon, 20 Aug 2007 15:26:00 +0000</pubDate><atom:updated>2011-01-05T00:33:02.262-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>c++</category><category domain='http://www.blogger.com/atom/ns#'>exception</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>c++ of the day</category><title>C++ of the Day #42 - Use of std::bad_exception</title><description>이번 글은 &lt;a href="http://cpptruths.blogspot.com/2007/05/use-of-stdbadexception.html"&gt;Use of std::bad_exception&lt;/a&gt;을 보고 작성하였습니다.&lt;br/&gt;&lt;br/&gt;아래 프로그램의 실행 결과는 무엇일까요?&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp" lineno="1"&gt;void my_unexpected() {&lt;br/&gt;  if (!uncaught_exception())&lt;br/&gt;    cerr &lt;&lt; "my_unexpected() called\n";&lt;br/&gt;  throw;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;void my_terminate() {&lt;br/&gt;  cerr &lt;&lt; "my_terminate() called\n";&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;void func() {&lt;br/&gt;  cerr &lt;&lt; "func() called\n";&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;void g() throw (int) {&lt;br/&gt;  throw 1.0; // throws double&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;int main()&lt;br/&gt;{&lt;br/&gt;  set_unexpected (my_unexpected);&lt;br/&gt;  set_terminate (my_terminate);&lt;br/&gt;  atexit (func);&lt;br/&gt;  try {&lt;br/&gt;    g();&lt;br/&gt;  }&lt;br/&gt;  catch (int) {&lt;br/&gt;    cerr &lt;&lt; "caught int\n";&lt;br/&gt;  }&lt;br/&gt;  catch (bad_exception&amp; e) {&lt;br/&gt;    cerr &lt;&lt; "caught bad_exception\n";&lt;br/&gt;  }&lt;br/&gt;  return 0;&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;한 단계씩 살펴보도록 하겠습니다. 먼저 main() 함수의 처음 세 라인은 각각 unexpected, terminate 함수와 프로그램 종료시 호출될 함수를 등록하고 있습니다. 그리고 C++03에서 unexpected() 함수와 관련된 내용은 다음과 같습니다.&lt;br/&gt;&lt;br/&gt;&lt;ol&gt;&lt;br/&gt;&lt;li&gt;exception-specification을 가진 함수에서 exception-specification에 리스트되어 있지 않은 예외를 던지면 호출된다.&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;&lt;li&gt;unexpected 함수안에서 exception-specification에 있는 예외를 던지면 해당 handler를 찾아 처리한다.&lt;/li&gt;&lt;br/&gt; &lt;br/&gt;&lt;li&gt;unexpected 함수안에서 rethrow 하거나 exception-specification에 없는 예외를 던지면...&lt;br/&gt;&lt;ul&gt;&lt;br/&gt;&lt;li&gt;exception-specification에 std::bad_exception이 있으면 던져진 예외는 std::bad_exception으로 치환되어 처리된다.&lt;/li&gt;&lt;br/&gt;&lt;li&gt;exception-specification에 std::bad_exception이 없으면 terminate() 함수가 호출된다.&lt;/li&gt;&lt;br/&gt;&lt;/ul&gt;&lt;br/&gt;&lt;/li&gt;&lt;br/&gt;&lt;br/&gt;&lt;/ol&gt;&lt;br/&gt;&lt;br/&gt;이제 main() 함수를 살펴 보죠. try 블록 안에서 g() 함수를 호출하고 있는데 g() 함수의 exception-specification에는 int 타입만이 존재합니다. 하지만 g() 함수에서는 double 타입을 던지고 있죠. 따라서 제일 먼저 unexpected 함수가 호출됩니다.&lt;br/&gt;&lt;br/&gt;다음으로 unexpected() 함수에서는 원래 예외를 그대로 rethrow하고 있는데 g() 함수의 exception-specification에는 std::bad_exception이 없습니다. 따라서 terminate() 함수가 호출됩니다. terminate() 함수는 abort() 함수를 호출하게 되고 abort() 함수의 경우 atexit()로 등록한 함수들이 호출되지 않게 됩니다. ((C++03, 3.6.3.4. Calling the function &lt;strong&gt;void abort();&lt;/strong&gt; declared in &amp;lt;cstdlib&gt; terminates the program without executing destructors for objects of automatic or static storage duration and without calling the functions passed to atexit(). ))&lt;br/&gt;&lt;br/&gt;따라서 위 프로그램의 결과는 다음과 같습니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="sh"&gt;&lt;br/&gt;my_unexpected() called&lt;br/&gt;my_terminate() called&lt;br/&gt;Abort (core dumped) &lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;그럼 위 프로그램에서 g() 함수의 exception-specification에 다음과 같이 std::bad_exception을 추가하면 결과는 어떻게 될까요?&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;void g() throw (std::bad_exception, int) {&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;unexpected에서 rethrow한 double 타입의 예외는 std::bad_exception으로 치환되어 처리됩니다. 그리고 exception handler에 std::bad_exception을 처리하는 handler가 있으므로 이 handler에서 처리되고 프로그램은 정상적으로 종료됩니다.&lt;br/&gt;&lt;br/&gt;프로그램 종료시에 atexit()로 등록한 함수가 호출되므로 프로그램의 결과는 다음과 같습니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="sh"&gt;&lt;br/&gt;my_unexpected() called&lt;br/&gt;caught bad_exception&lt;br/&gt;func() called&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;마지막으로 위의 프로그램에서 아직 설명하지 않은 함수가 하나 있는데 바로 uncaught_exception()입니다. C++03에는 다음과 같이 설명되어 있습니다.&lt;br/&gt;&lt;br/&gt;&lt;blockquote&gt;&lt;br/&gt;18.6.4 uncaught_exception [lib.uncaught]&lt;br/&gt;&lt;strong&gt;bool uncaught_exception() throw();&lt;/strong&gt;&lt;br/&gt;1 Returns: true after completing evaluation of a throw-expression until either completing initialization of the exception-declaration in the matching handler or entering unexpected() due to the throw; or after entering terminate() for any reason other than an explicit call to terminate(). [Note: This includes stack unwinding (15.2). --end note]&lt;br/&gt;&lt;br/&gt;2 Notes: When uncaught_exception() is true, throwing an exception can result in a call of terminate() (15.5.1).&lt;br/&gt;&lt;/blockquote&gt;&lt;br/&gt;&lt;br/&gt;간단히 설명하면 예외가 던져진 후부터 어떤 handler가 catch 하기 전까지만 true를 리턴하는 함수입니다. 당연하게도 handler가 다시 rethrow하게 되면  다른 handler가 받기 전까지 다시 true를 리턴합니다. ((기본적인 uncaught_exception() 함수의 동작을 위해 &lt;a href="http://msdn2.microsoft.com/en-us/library/k1atwat8(VS.80).aspx"&gt;여기&lt;/a&gt; 코드를 참고하세요.))&lt;br/&gt;&lt;br/&gt;위의 코드와 같이 던져진 예외에 의해 호출된 unexpected() 함수안에서 uncaught_exception() 함수의 리턴 값은 위에 언급된 대로 true가 되어야 합니다. 하지만 위의 결과를 보면 my_unexpected() 함수안에서 호출된 uncaught_exception() 함수가 false를 리턴했음을 알 수 있습니다. 이 점에 있어서는 g++가 표준을 따르지 않음을 알 수 있습니다. ((&lt;a href="http://msdn2.microsoft.com/en-us/library/aa903425(VS.71).aspx"&gt;여기&lt;/a&gt;를 보니 VC++에서는 무조건 false를 리턴하도록 구현되어 있군요.))&lt;br/&gt;&lt;br/&gt;그럼 왜 표준에선 이런 함수를 정의해 놓았을까요? 이유는 exception이 처리되면서 발생하는 stack unwinding과 관계가 있습니다. stack unwinding이 시작되면 해당 stack에 있는 객체들의 소멸자들이 호출됩니다. 그런데 exception에 의한 stack unwinding시 호출되는 소멸자에서 다시 exception이 던져되면 바로 terminate()가 호출됩니다. ((C++03, 15.2.3. [Note: If a destructor called during stack unwinding exits with an exception, terminate is called (15.5.1). So destructors should generally catch exceptions and not let them propagate out of the destructor. --end note] ))&lt;br/&gt;&lt;br/&gt;이런 이유로 소멸자에선 예외가 빠져나가게 해서는 안된다라는 규칙도 생긴거죠. 이런 경우 uncaught_exception을 사용하여 소멸자에서 uncaught_exception의 리턴 값이 false인 경우에만 예외를 던지게 되면 terminate가 불리지 않게 할 수 있습니다. ((물론 &lt;a href="http://www.gotw.ca/gotw/047.htm"&gt;Uncaught Exceptions&lt;/a&gt;에 보면 이런 사용법은 여러가지 문제가 있기 때문에 사용해서는 안됩니다.)) 이런 관점에서 봤을 때는 현재 g++에서의 구현이 C++03보다 더 맞는 것으로 보이기도 합니다. unexpected() 함수에서는 예외를 던지더라도 terminate()가 호출되진 않으니까요. :-)&lt;br/&gt;&lt;br/&gt;마지막으로 &lt;a href="http://www.gotw.ca/publications/mill22.htm"&gt;A Pragmatic Look at Exception Specifications&lt;/a&gt;에 있듯이 exception specification의 사용은 권장되지 않습니다.&lt;br/&gt;&lt;br/&gt;사용이 권장되지 않는 exception specification과 uncaught_exception() 함수에 대해 너무 길게 써버렸네요. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-8688599884601951648?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/08/c-of-day-42-use-of-stdbadexception.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-3686465508048729088</guid><pubDate>Mon, 13 Aug 2007 16:51:00 +0000</pubDate><atom:updated>2011-01-05T00:33:02.240-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>c++</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>pimpl</category><category domain='http://www.blogger.com/atom/ns#'>c++ of the day</category><title>C++ of the Day #41 - Maintaining const in Impl classes</title><description>이번 내용은 c.l.c.m.에 올라온 &lt;a href="http://groups.google.co.kr/group/comp.lang.c++.moderated/browse_thread/thread/e19e65ff45d8deb9"&gt; Maintaining const in Impl classes&lt;/a&gt;라는 글에서 가지고 왔습니다. &lt;a href="http://www.gotw.ca/gotw/024.htm"&gt;Pimpl Idiom&lt;/a&gt;과 const correctness에 관한 글입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;struct Foo {&lt;br/&gt;  struct Impl {&lt;br/&gt;    void A() const { }; // unreachable code!&lt;br/&gt;    void A() { };&lt;br/&gt;  };&lt;br/&gt;&lt;br/&gt;  Foo() : pimpl_(new Impl) { };&lt;br/&gt;&lt;br/&gt;  void A() const { pimpl_-&gt;A(); };&lt;br/&gt;  void A() { pimpl_-&gt;A(); };&lt;br/&gt;&lt;br/&gt;  Impl* pimpl_;&lt;br/&gt;};&lt;br/&gt;&lt;br/&gt;// ...&lt;br/&gt;Foo const foo;&lt;br/&gt;foo.A(); // will always call non-const Foo::Impl::A()&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;위의 코드에서 문제라고 얘기되고 있는 것은 foo가 Foo 클래스의 const instance인데 Impl의 A() const가 호출되지 않고 A()가 호출된다는 점입니다.&lt;br/&gt;&lt;br/&gt;원인은 간단합니다. foo가 const instance라서 const가 되는 것은 Impl*이지 Impl이 아니기 때문입니다. Impl* const냐 Impl const*냐의 차이죠. ((const 관련 내용이 얼마전 시즈하님의 &lt;a href="http://sizuha.egloos.com/3327098"&gt;C 포인터, 확실히 알자(6) - 상수와 포인터&lt;/a&gt;에도 올라왔었습니다.))&lt;br/&gt;&lt;br/&gt;무엇의 const인지 쉽게 알기 위해서는 const 키워드의 바로 앞에 무엇이 있는지 보면 됩니다. 예를 들어보죠.&lt;br/&gt;&lt;br/&gt;&lt;ul&gt;&lt;br/&gt;	&lt;li&gt;T const* -&gt; T가 const&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;T* const -&gt; T*가 const&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;std::auto_ptr&amp;lt;T const&gt; -&gt; T가 const&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;std::auto_ptr&amp;lt;T&gt;  const -&gt; std::auto_ptr&amp;lt;T&gt;가 const&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;boost::shared_ptr&amp;lt;T const&gt; -&gt; T가 const&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;boost::shared_ptr&amp;lt;T&gt;  const -&gt; boost::shared_ptr&amp;lt;T&gt;가 const&lt;/li&gt;&lt;br/&gt;&lt;/ul&gt;&lt;br/&gt;&lt;br/&gt;위 공식(?)에 맞추기 위해 const T* 대신 T const* 라고 썼습니다. 게다가 몇 년전부터 T const* 형식이 유행인 듯... 왠지 멋져 보입니다. :-)&lt;br/&gt;&lt;br/&gt;따라서 위의 문제에서 Impl::A() const 함수가 불리게 하기 위한 가장 간단한 방법은 Foo::A() const를 다음과 같이 수정하는 것입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;void Foo::A() const {&lt;br/&gt;  const_cast&lt;Impl const*&gt;(pimpl_)-&gt;A();&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;만약 다뤄야 할 멤버 함수가 많다면 다음과 같이 get_impl()같은 helper 함수를 만들어 사용하는 것이 좋겠죠?&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;struct Foo {&lt;br/&gt;  struct Impl {&lt;br/&gt;    void A() const { };&lt;br/&gt;    void A() { };&lt;br/&gt;  };&lt;br/&gt;&lt;br/&gt;  Impl* get_pimpl() { return pimpl_; }&lt;br/&gt;  Impl const* get_pimpl() const { return pimpl_; }&lt;br/&gt;&lt;br/&gt;  Foo() : pimpl_(new Impl) { };&lt;br/&gt;&lt;br/&gt;  void A() const { get_pimpl()-&gt;A(); };&lt;br/&gt;  void A() { get_pimpl()-&gt;A(); };&lt;br/&gt;&lt;br/&gt;  Impl* pimpl_;&lt;br/&gt;};&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;&lt;a href="http://groups.google.co.kr/group/comp.lang.c++.moderated/browse_thread/thread/e19e65ff45d8deb9"&gt;원본 링크&lt;/a&gt;의 김승범님 답변을 보면 이 용도의 PimplPtr라는 smart pointer 클래스도 볼 수 있습니다. 이 PimplPtr는 일반 smart pointer와는 다르게 T* 대신 T const*를 리턴하도록 구현되어 있죠.&lt;br/&gt;&lt;br/&gt;개인적으론 Impl 클래스는 말 그대로 원래 클래스의 private에 해당하는 코드로 그 클래스에서만 사용하는 코드들인데 굳이 const correctness까지 필요할까라는 생각이 드네요. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-3686465508048729088?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/08/c-of-day-41-maintaining-const-in-impl.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-7310798312656906786</guid><pubDate>Fri, 10 Aug 2007 15:01:00 +0000</pubDate><atom:updated>2011-01-05T00:33:02.173-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>quiz</category><category domain='http://www.blogger.com/atom/ns#'>algorithm</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><title>1의 개수 세기 - 해답</title><description>벌써 어제 말한 내일이 되었는데 답을 주신 분이 아무도 없어서 좀 뻘쭘하네요. :-P&lt;br/&gt;&lt;br/&gt;그리고 어제 문제에 O(1)이라고 적었는데 엄밀히 얘기하자면 O(log&lt;sub&gt;10&lt;/sub&gt; n)이라고 적었어야 했네요. 죄송합니다.&lt;br/&gt;&lt;br/&gt;...&lt;br/&gt;&lt;br/&gt;문제를 잠시 생각해보면 1~n까지의 수들 중 1의 개수를 얻기 위해서는 해당 숫자 n의 각 자리의 1의 개수가 모두 몇개나 될지를 구해서 더하면 된다는 사실을 알 수 있습니다.&lt;br/&gt;&lt;br/&gt;예를 들어 13이라는 수를 생각해 보면 1~13까지의 수에서 1의 자리에는 1이 모두 몇개나 되는지와 10의 자리에는 모두 몇개나 되는지를 구해 이 값을 더하면 됩니다. 먼저 1의 자리를 생각해 보면 1, 11의 두 개가 있으며 10의 자리의 경우, 10, 11, 12, 13의 네 개가 있습니다. 따라서 2+4=6이라는 값을 구할 수 있습니다.&lt;br/&gt;&lt;br/&gt;이번엔 234라는 수에서 10의 자리를 예로 들어 살펴 보겠습니다. 1~234라는 수들 중 10의 자리에 1이 들어가는 수는 10, 11, ..., 19, 110, 111, ... 119, 210, 211, ..., 219들로 모두 30개가 있음을 알 수 있습니다. 이 규칙들을 보면 해당 자리수의 1의 개수를 구하는 공식을 만들 수 있습니다.&lt;br/&gt;&lt;br/&gt;234의 10의 자리에 해당하는 1의 개수는 ((234/100)+1)*10이 됩니다. 여기서 +1은 해당 자리수의 수가 0이 아닌 경우에만 더해집니다. 예를 들어 204라면 ((204/100)+0)*10으로 30개가 아닌 20개가 됩니다.&lt;br/&gt;&lt;br/&gt;이런 방식으로 234의 각 자리수의 1의 개수를 구하면 1의 자리에 해당하는 1의 개수는 ((234/10)+1)*1=24개가 되고 100의 자리에 해당하는 개수는 ((234/1000)+1)*100=100이 됩니다. 이들 세 수를 모두 합하면 24+30+100=154개가 됩니다.&lt;br/&gt;&lt;br/&gt;한가지 추가로 생각해야 할 점은 제일 큰 자리의 수가 1인 경우 위의 공식이 아닌 다른 공식이 필요하다는 점입니다. 예를 들어 123에서 100의 자리에 해당하는 1의 개수는 ((123/1000)+1)*100=100이 아니라 (123-100)+1=24가 됩니다.&lt;br/&gt;&lt;br/&gt;설명이 복잡했지만 코드를 보면 간단합니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;typedef long long int64;&lt;br/&gt;&lt;br/&gt;int count1(int64 orig_n)&lt;br/&gt;{&lt;br/&gt;  if (orig_n == 0) return 0;&lt;br/&gt;&lt;br/&gt;  int64 n = orig_n;&lt;br/&gt;&lt;br/&gt;  int64 cnt = 0;&lt;br/&gt;  int64 times = 1;&lt;br/&gt;&lt;br/&gt;  while (n &gt;= 10) {&lt;br/&gt;    int r = n % 10;&lt;br/&gt;    n /= 10;&lt;br/&gt;    cnt += (n + (r != 0)) * times;&lt;br/&gt;    times *= 10;&lt;br/&gt;  }&lt;br/&gt;&lt;br/&gt;  if (n &gt; 1)&lt;br/&gt;    cnt += times;&lt;br/&gt;  else&lt;br/&gt;    cnt += orig_n - times + 1;&lt;br/&gt;&lt;br/&gt;  return cnt;&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;참고로 1의 개수에는 다음과 같은 규칙도 있습니다. 정수의 세계란 참으로 오묘합니다. :-)&lt;br/&gt;&lt;br/&gt;&lt;pre lang="sh"&gt;&lt;br/&gt;$ ./a.out 9&lt;br/&gt;1&lt;br/&gt;$ ./a.out 99&lt;br/&gt;20&lt;br/&gt;$ ./a.out 999&lt;br/&gt;300&lt;br/&gt;$ ./a.out 9999&lt;br/&gt;4000&lt;br/&gt;$ ./a.out 99999&lt;br/&gt;50000&lt;br/&gt;$ ./a.out 999999&lt;br/&gt;600000&lt;br/&gt;$ ./a.out 9999999&lt;br/&gt;7000000&lt;br/&gt;$ ./a.out 99999999&lt;br/&gt;80000000&lt;br/&gt;$ ./a.out 999999999&lt;br/&gt;900000000&lt;br/&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-7310798312656906786?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/08/1_10.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-5192358187670765207</guid><pubDate>Thu, 09 Aug 2007 13:17:00 +0000</pubDate><atom:updated>2011-01-05T00:33:02.153-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>quiz</category><category domain='http://www.blogger.com/atom/ns#'>algorithm</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><title>1의 개수 세기</title><description>저도 간단한 알고리즘 문제 하나... :-)&lt;br/&gt;&lt;br/&gt;어떤 수 n이 주어졌을때 1~n까지의 수를 쭈욱 썼을때 나오는 1의 개수를 구하는 문제입니다.&lt;br/&gt;&lt;br/&gt;예를 들어 13이라는 수가 주어지면 1~13까지의 수 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13에서 1은 1, 10, 11, 12, 13에 나오며 그 개수는 6이 됩니다. 즉, f(13)=6.&lt;br/&gt;&lt;br/&gt;&lt;a href="http://forum.java.sun.com/thread.jspa?threadID=699794&amp;messageID=4061267"&gt;원래 문제&lt;/a&gt;는 f(n)=n이 되는 1이 아닌 가장 작은 수를 구하는 문제인데 이 문제의 경우에는 처음부터 쭈욱 세어나가면 되기 때문에 간단히 다음과 같이 구현을 하면 됩니다. ((한가지 주의할 점은 이전에 찾았던 n-1값을 사용하지 않고 다시 처음부터 n까지 값을 계산하면 시간이 너무 많이 걸린다는 점입니다. 위의 코드에서는 static 변수를 사용하여 이전 값에 계속 더해나가는 방법을 사용했습니다.))&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;#include &lt;iostream&gt;&lt;br/&gt;&lt;br/&gt;int count1(int n)&lt;br/&gt;{&lt;br/&gt;  static int cnt = 1; // not 0 because n starts from 2. see main.&lt;br/&gt;&lt;br/&gt;  while (n &gt; 0) {&lt;br/&gt;    if ((n % 10) == 1) ++cnt;&lt;br/&gt;    n /= 10;&lt;br/&gt;  }&lt;br/&gt;&lt;br/&gt;  return cnt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;int main()&lt;br/&gt;{&lt;br/&gt;  using namespace std;&lt;br/&gt; &lt;br/&gt;  int n = 2;&lt;br/&gt;&lt;br/&gt;  while (count1(n) != n) ++n;&lt;br/&gt;  cout &lt;&lt; n &lt;&lt; endl;&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;좀 재미가 없죠? 그래서 이번 문제는 어떤 수 n에 대해서 f(n)을 O(1)시간에 구하는 알고리즘을 만드는 것입니다. 관심있으신 분들은 한번 풀어보세요. 제가 만든 코드는 내일 올려보겠습니다.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-5192358187670765207?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/08/1.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-2833684151720305169</guid><pubDate>Wed, 08 Aug 2007 08:40:00 +0000</pubDate><atom:updated>2011-01-05T00:33:01.996-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>trackback</category><category domain='http://www.blogger.com/atom/ns#'>quiz</category><category domain='http://www.blogger.com/atom/ns#'>algorithm</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><title>어떤 두 정수의 합이 주어진 숫자가 되는 경우가 있는가?</title><description>art.oriented에 올라온 &lt;a href="http://minjang.egloos.com/1392478"&gt;어떤 두 정수의 합이 주어진 숫자가 되는 경우가 있는가?&lt;/a&gt;라는 글의 트랙백입니다. &lt;br/&gt;&lt;br/&gt;코드가 비교적 단순해서 코드만 보시면 어떤 방법인지 아실 수 있습니다. 실행 파일을 만들 수 있는 전체 코드입니다. (에러 체크같은건 없습니다. ;-) )&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;#include &lt;iostream&gt;&lt;br/&gt;&lt;br/&gt;using namespace std;&lt;br/&gt;&lt;br/&gt;int main(int argc, char *argv[])&lt;br/&gt;{&lt;br/&gt;  int V[] = { 1, 4, 7, 9, 10 };&lt;br/&gt;  int N = sizeof(V) / sizeof(*V);&lt;br/&gt;&lt;br/&gt;  int K = atoi(argv[1]);&lt;br/&gt;&lt;br/&gt;  int* l = V;&lt;br/&gt;  int* r = V + N - 1;&lt;br/&gt;&lt;br/&gt;  while (l &lt; r) {&lt;br/&gt;    int sum = *l + *r;&lt;br/&gt;&lt;br/&gt;    if (sum &lt; K) ++l;&lt;br/&gt;    else if (sum &gt; K) --r;&lt;br/&gt;    else break; // sum == K&lt;br/&gt;  }&lt;br/&gt;&lt;br/&gt;  if (l &lt; r) cout &lt;&lt; "found(" &lt;&lt; *l &lt;&lt; ", " &lt;&lt; *r &lt;&lt; ")\n";&lt;br/&gt;  else cout &lt;&lt; "not found\n";&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;간단히 설명하면, 제일 작은 수와 제일 큰 수를 각각 left, right로 놓고 이 두 수의 합을 원하는 값과 비교합니다. 만약 두 수의 합이 원하는 값보다 작다면 left를 다음 작은 수로 설정합니다. 이와 반대로 원하는 값보다 크다면 right를 다음 큰 값으로 놓습니다. 같으면 원하는 숫자의 합이 발견된 것이므로 바로 종료합니다.&lt;br/&gt;&lt;br/&gt;적어 보니 그냥 단순 searching인것 같은데... 맞나요? :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-2833684151720305169?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/08/blog-post.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>7</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-5782469658565534424</guid><pubDate>Mon, 30 Apr 2007 13:23:00 +0000</pubDate><atom:updated>2011-01-05T00:33:01.972-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>c++</category><category domain='http://www.blogger.com/atom/ns#'>command line option</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>c++ of the day</category><title>C++ of the Day #40 - Python의 OptionParser 클래스 따라잡기</title><description>텍스트 기반 프로그램을 만들때 필요한 기능중의 하나가 command line option들을 parsing 해주는 것입니다. 원래는 &lt;a href="http://www.boost.org/doc/html/program_options.html"&gt;boost::program_options 라이브러리&lt;/a&gt;를 소개하는 글을 쓰려고 했습니다. 그런데 마침 Python을 사용하면서 알게 된 &lt;a href="http://docs.python.org/lib/module-optparse.html"&gt;OptionParser 클래스&lt;/a&gt;가 좀 더 사용하기가 쉬운 것 같아 이 클래스를 C++ 버전으로 만들어 보았습니다.&lt;br/&gt;&lt;br/&gt;boost::program_options 라이브러리와는 달리 &lt;a href="http://www.boost.org/doc/html/program_options/howto.html#id2716014"&gt;옵션들의 grouping&lt;/a&gt;이나 &lt;a href="http://www.boost.org/doc/html/program_options/tutorial.html#id2714557"&gt;설정 파일을 사용하는 기능&lt;/a&gt;은 구현되어 있지 않습니다.&lt;br/&gt;&lt;br/&gt;그리고 옵션들의 타입은 모두 string이나 vector&amp;lt;string&gt;을 사용합니다. boost::program_options과 같이 as&amp;lt;int&gt; 하는 식의 함수를 제공할 수도 있었습니다만 이렇게 하려면 exception들을 정의해야 하기 때문에 생략하였습니다. 필요하다면 다음과 같이 boost::lexical_cast를 사용하면 됩니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;int blocksize = boost::lexical_cast&lt;int&gt;(opts.get(BlockSizeOpt));&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;그리고 OptionParser 클래스는 getopt_long을 사용하여 구현되었기 때문에 parsing하는 방법은 &lt;a href="http://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html"&gt;GNU coding standards&lt;/a&gt;를 따릅니다.&lt;br/&gt;&lt;br/&gt;Command line option에는 short form과 long form이 있습니다. 예를 들어 -I는 short form, --include-path는 long form입니다. 또한 어떤 옵션은 여러개의 값을 가질 수도 있습니다. gcc의 -I 옵션은 여러개의 값을 가질 수 있는 옵션의 예입니다.&lt;br/&gt;&lt;br/&gt;그럼 이제 OptionParser의 사용법을 하나씩 알아보겠습니다. 먼저 OptionParser를 다음과 같이 생성합니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;    OptionParser op("Usage: %prog [options] arg1 arg2 ...", // usage&lt;br/&gt;		    "1.0",                                  // version&lt;br/&gt;		    "Report bugs to &lt;mailing-address&gt;."     // message&lt;br/&gt;		    );&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;첫번째 인자는 usage 문자열이고 다음으로 version, message 문자열을 넣어 줍니다. usage나 version 문자열에 %prog를 넣으면 이 부분은 argv[0]로 변경되어 출력됩니다. 마지막으로 message는 help 화면의 마지막에 출력될 메시지를 넣습니다. (조금 뒤에 나오는 예제 화면을 보시면 이해가 쉽습니다.)&lt;br/&gt;&lt;br/&gt;다음으로 위에서 생성한 OptionParser를 사용하여 parse_args 함수를 호출합니다. 결과는 OptMap과 OptArgs에 각각 저장됩니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;    OptMap optmap;&lt;br/&gt;    OptArgs args;&lt;br/&gt;    boost::tie(optmap, args) = op.parse_args(argc, argv);&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;여기까지 작성하고 빌드하여 실행시킨 결과는 다음과 같습니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="sh"&gt;&lt;br/&gt;$ ./a.out --help&lt;br/&gt;Usage: ./a.out [options] arg1 arg2 ...&lt;br/&gt;&lt;br/&gt;Options:&lt;br/&gt;  -V, --version          show program's version number and exit&lt;br/&gt;  -h, --help             show this help message and exit&lt;br/&gt;&lt;br/&gt;Report bugs to &lt;mailing-address&gt;.&lt;br/&gt;&lt;br/&gt;$ ./a.out --version&lt;br/&gt;1.0&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;위의 결과에서 알 수 있듯이 --help와 --version 옵션은 OptionParser 클래스에 의해 자동적으로 제공됩니다.&lt;br/&gt;&lt;br/&gt;그럼 이제 필요한 인자를 하나씩 만들어 보겠습니다. 다음 라인은 -a, --all 옵션을 추가하는 코드입니다. 마지막 문자열은 --help 화면에 출력될 help string입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;    op.add_option('a', "all", "do not hide entries starting with .");&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;이 옵션이 입력되었는지 확인하는 방법은 parse_args에서 리턴된 OptMap의 test함수를 사용하는 것입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;    if (optmap.test('a')) allflags = true;&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;test함수에서 사용되는 키는 add_option 호출시 short form에 사용된 값입니다. Long form만 제공하는 옵션을 만들기 위해서는 다음과 같이 별도의 값을 지정해야 하는데 이때 OptionParser의 UserOpt 이상의 값중에서 사용해야 합니다. 따라서 이런 옵션이 다수 있는 경우 다음과 같이 enum 을 만들어 사용하는 것이 좋습니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;    enum Opt&lt;br/&gt;    {&lt;br/&gt;      AuthorOpt = OptionParser::UserOpt,&lt;br/&gt;      ...&lt;br/&gt;    };&lt;br/&gt;&lt;br/&gt;       add_option(AuthorOpt, "author", "print the author of each file")&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;이 값이 입력되었는지 확인하기 위해서는 위의 경우와 마찬가지로 이 값을 사용하여 test 함수를 호출하면 됩니다.&lt;br/&gt;&lt;br/&gt;다음으로 --block-size=30 이라든지 --color=always와 같이 인자가 필요한 옵션을 추가하는 방법에 대해 알아보겠습니다. &lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;      .add_option(BlockSizeOpt, "block-size", "use SIZE-byte blocks", "SIZE")&lt;br/&gt;      .add_option(ColorOpt, "color",&lt;br/&gt;		  "control whether color is used to distinguish file\n"&lt;br/&gt;		  "  types.  WHEN may be `never', `always', or `auto'\n"&lt;br/&gt;		  "[default: %default]",&lt;br/&gt;		  "WHEN",&lt;br/&gt;		  "auto")&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;인자가 필요한 경우 help string 뒤에 metavar 인자를 넘깁니다. 이 인자가 null string이 아닌 경우를 인자가 필요한 옵션으로 간주하여 처리합니다. 추가로 이 값은 --help 화면에 --block-size=SIZE와 같이 출력되는 역할을 합니다.&lt;br/&gt;&lt;br/&gt;두번째 --color 옵션의 경우에는 metavar외에 추가로 인자를 하나 더 가지고 있는데 이 인자는 default value를 나타냅니다. Default value가 있는 옵션은 인자가 필요하지만 입력되지 않은 경우에도 에러로 처리되지 않고 default value가 입력된 것처럼 처리됩니다. 이 경우 help string의 %default 부분은 "auto"값으로 변경되어 출력됩니다.&lt;br/&gt;&lt;br/&gt;마지막으로 gcc의 -I 옵션처럼 여러개의 값을 가질 수 있는 인자를 만들려면 add_option 함수 대신 add_multi_option 함수를 사용합니다. 사용 방법은 default value를 지정할 수 없다는 점과 metavar가 항상 null string이 아니어야 한다는 점을 제외하곤 동일합니다.&lt;br/&gt;&lt;br/&gt;Parsing 결과에서 옵션의 인자를 얻는 방법은 다음과 같습니다. 리턴 값은 string입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;    if (optmap.test(BlockSizeOpt)) {&lt;br/&gt;      blocksize = boost::lexical_cast&lt;int&gt;(optmap.get(BlockSizeOpt));&lt;br/&gt;    }&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;여러개의 인자를 가지는 옵션의 결과는 vector&amp;lt;string&gt;로 리턴됩니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="c++"&gt;&lt;br/&gt;template &lt;class T&gt;&lt;br/&gt;std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, std::vector&lt;T&gt; const&amp; cont)&lt;br/&gt;{&lt;br/&gt;  std::copy(cont.begin(), cont.end(), std::ostream_iterator&lt;T&gt;(os, " "));&lt;br/&gt;  return os;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;...&lt;br/&gt;&lt;br/&gt;    if (optmap.test('I')) {&lt;br/&gt;      cout &lt;&lt; "-I=" &lt;&lt; optmap.get_multi('I') &lt;&lt; endl;&lt;br/&gt;    }&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;마지막으로 parse_args함수에서 리턴되는 tuple중 두번째 값인 OptArgs에는 옵션 이외의 인자들이 vector&amp;lt;string&gt;의 형태로 리턴됩니다. 예를 들어 "gcc -o a.out 1.cpp 2.cpp" 를 parse_arg하면 OptArgs에는 1.cpp, 2.cpp 두개의 값이 들어 있게 됩니다.&lt;br/&gt;&lt;br/&gt;다음 화면은 첨부된 test.cpp를 빌드하여 만든 실행 파일의 --help입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="sh"&gt;&lt;br/&gt;Usage: ./a.out [options] arg1 arg2 ...&lt;br/&gt;&lt;br/&gt;Options:&lt;br/&gt;  -V, --version          show program's version number and exit&lt;br/&gt;  -h, --help             show this help message and exit&lt;br/&gt;  -a, --all              do not hide entries starting with .&lt;br/&gt;      --author           print the author of each file&lt;br/&gt;      --block-size=SIZE  use SIZE-byte blocks&lt;br/&gt;  -c                     with -lt: sort by, and show, ctime (time of last&lt;br/&gt;                           modification of file status information)&lt;br/&gt;                           with -l: show ctime and sort by name&lt;br/&gt;                         otherwise: sort by ctime&lt;br/&gt;  -H, --dereference-command-line&lt;br/&gt;                         follow symbolic links on the command line&lt;br/&gt;      --color=[WHEN]     control whether color is used to distinguish file&lt;br/&gt;                           types.  WHEN may be `never', `always', or `auto'&lt;br/&gt;                         [default: auto]&lt;br/&gt;  -I, --include-path=PATH&lt;br/&gt;                         list of search path&lt;br/&gt;&lt;br/&gt;Report bugs to &lt;mailing-address&gt;.&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;.&lt;br/&gt;&lt;br/&gt;구현된 내용에 대해 설명을 하려고 했는데 막상 만들고 나니 별로 설명할 내용이 없네요. :roll: 구현을 위해 boost::variant와 static_visitor의 사용하고 있습니다. 참고하실 분들은 한번 보세요.&lt;br/&gt;&lt;br/&gt;소스 코드는 &lt;a href="http://ideathinking.com/wiki/images/b/b2/Optparse.tar.gz"&gt;여기&lt;/a&gt;서 다운로드하시면 됩니다. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-5782469658565534424?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/04/c-of-day-40-python-optionparser.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-2903403860057687119</guid><pubDate>Wed, 25 Apr 2007 12:43:00 +0000</pubDate><atom:updated>2011-01-05T00:33:01.862-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>thinking</category><category domain='http://www.blogger.com/atom/ns#'>bad smell</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><category domain='http://www.blogger.com/atom/ns#'>refactoring</category><title>Bad smell in mind</title><description>Refactoring을 읽어 보면 &lt;a href="http://wiki.java.net/bin/view/People/SmellsToRefactorings"&gt;bad smell in code&lt;/a&gt;라는 말이 나옵니다. 코드에서 나쁜 냄새가 느껴질 때가 refactoring을 해야 할 때라는 내용이죠. &lt;br/&gt;&lt;br/&gt;예전에 했던 생각인데 bad smell을 꼭 코드에서만 맡을 수 있는 것은 아닌 것 같습니다. 제목에 쓴 것처럼 뭔가 심리적인 bad smell이 있을 것 같은데 제가 생각했던 한가지 bad smell in mind는 바로 이것입니다.&lt;br/&gt;&lt;br/&gt;&lt;blockquote&gt;내 코드를 남들에게 보여주기 부끄럽다.&lt;/blockquote&gt;&lt;br/&gt;&lt;br/&gt;이 냄새를 맡게 되면 역시 refactoing을 시작해야 합니다. 보통은 주석을 통한 탈취 처리로 마무리되는 경우가 많지만 말이죠.&lt;br/&gt;&lt;br/&gt;저는 예전보다는 이 냄새를 자주 맡을 수 없게 되었는데 이유를 생각해 보니 다음 중 하나일 것 같습니다.&lt;br/&gt;&lt;br/&gt;&lt;ol&gt;&lt;br/&gt;	&lt;li&gt;나이가 한살 두살 많아지며 부끄러운 줄 모르게 되었다. 8-O&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;코드를 정말 잘 작성하게 되었다.&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;주변에 내 코드에서 냄새를 맡을 수 있는 사람이 없다.&lt;/li&gt;&lt;br/&gt;&lt;/ol&gt;&lt;br/&gt;&lt;br/&gt;제발 1번은 아니었으면 하는 것이 개인적인 바램. 물론 2번이었으면 하는데 이것도 썩 믿기질 않습니다. 결국 이유는 3번인 것 같습니다. 주변 사람들이 내가 코딩을 엉망으로  해놔도 엉망인지 알아보는 사람이 없다면 부끄럽지도 않겠죠. &lt;br/&gt;&lt;br/&gt;실력있는 사람들 옆에 있으면 특별히 배우는 것 없어도 발전할 수 있는 이유중의 하나가 이런 것이 아닌가 합니다. 그들의 작업만큼 멋지지 않은 내 것을 보고 부끄러움을 느끼고 더 잘 하려고 노력하는 것만으로도 스스로 발전하는 것이죠.&lt;br/&gt;&lt;br/&gt;처음 입사할 때는 대기업에 가면 훌륭한 개발자들이 많이 있겠지라는 생각을 했었습니다. 하지만 지금은 역시 대기업은 평균보다 &lt;em&gt;&lt;strong&gt;약간&lt;/strong&gt;&lt;/em&gt; 높은 수준의 인력을 &lt;em&gt;&lt;strong&gt;관리&lt;/strong&gt;&lt;/em&gt;하여 제품을 개발하는 곳이구나라는 생각을 합니다.&lt;br/&gt;&lt;br/&gt;물론 대기업에서 배울 수 있는 많은 것들이 있습니다. 큰 프로젝트 경험, 비싼 툴들, 관리 능력, 회사 생활, 인간 관계등등. 이중에서 제일 만족하고 있는 부분은 역시 큰 프로젝트 경험입니다. 100 man-year보다 큰 프로젝트들을 작은 회사에서 해보긴 어려울테니까요.&lt;br/&gt;&lt;br/&gt;하지만 이제는 큰 프로젝트 경험보단 멋진 개발자들과의 작업을 경험할 수 있었으면 좋겠습니다. :-|&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-2903403860057687119?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/04/bad-smell-in-mind.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>5</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-5528327799371258461.post-5268168263423193828</guid><pubDate>Mon, 23 Apr 2007 12:46:00 +0000</pubDate><atom:updated>2011-01-05T00:33:01.733-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>assert</category><category domain='http://www.blogger.com/atom/ns#'>programming</category><title>assert()와 NDEBUG</title><description>바로 이전 글에서 "디버깅 옵션으로 컴파일하니 문제가 없어져요"와 같은 주장을 엉뚱하다고 써놓고 제가 바로 그런 실수를 했네요. :-| 물론 이전 글과 같이 multi-threading 환경에서의 문제는 미묘한 타이밍 문제를 말하는 것이었지만 제가 한 실수는 바로 assert()와 관련이 있습니다.&lt;br/&gt;&lt;br/&gt;모든 C/C++ 책들에서 경고하듯이 assert() 안에는 실제 동작해야 하는 코드가 들어가서는 안되죠. 제가 한 실수는 바로 아래 보이는 코드입니다.&lt;br/&gt;&lt;br/&gt;&lt;pre lang="cpp"&gt;&lt;br/&gt;assert(pingback_.activate());&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;서버로부터 오는 ping 메시지에 응답하는 thread를 동작시키는 코드입니다.&lt;br/&gt;&lt;br/&gt;몇 주전 코드 테스트시에는 -g 옵션이 있어 이 코드가 제대로 동작을 했지요. 그런데 실제 환경에서 실행시켜보니 정확히 3분 30초마다 connection이 끊겼습니다. 서버와 클라이언트 사이의 ping 메시지에 문제가 있다고는 생각했지만 이전에 테스트했던 코드라 코드에 문제가 있으리라곤 생각도 안했지요.&lt;br/&gt;&lt;br/&gt;정말 사람 눈에는 믿는대로 보이는 것인지 문제의 라인을 여러번 훑어 봤지만 보이질 않더군요. 결국 퇴근해서 집에 가는 버스안에서 생각이 나서 다음날 수정할 수 있었습니다.&lt;br/&gt;&lt;br/&gt;물론 아직 제가 만들어서 저희 팀내에서만 테스트하는 코드라 큰 문제는 없었지만 옆 팀까지 사용하고 난 이후에 발생했으면 좀 부끄러웠겠네요. :roll:&lt;br/&gt;&lt;br/&gt;한가지 더... 왜 assert는 NDEBUG일때만 동작하는 유일한 매크로이면서 ASSERT와 같이 대문자를 사용하지 않았는지 좀 원망스럽습니다. :-x&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5528327799371258461-5268168263423193828?l=www.ideathinking.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ideathinking.com/2007/04/assert-ndebug.html</link><author>noreply@blogger.com (Wongoo Lee)</author><thr:total>4</thr:total></item></channel></rss>
