<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>笨頭哥的沒營養文章集 &#187; Programming</title>
	<atom:link href="http://blog.hubert.tw/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.hubert.tw</link>
	<description>Hubert&#039;s Blog</description>
	<lastBuildDate>Wed, 11 Jan 2012 16:34:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>用 Microsoft Translator API 翻譯 properties 檔案</title>
		<link>http://blog.hubert.tw/2012/01/11/%e7%94%a8-microsoft-translatorapi-%e7%bf%bb%e8%ad%af-properties-%e6%aa%94%e6%a1%88/</link>
		<comments>http://blog.hubert.tw/2012/01/11/%e7%94%a8-microsoft-translatorapi-%e7%bf%bb%e8%ad%af-properties-%e6%aa%94%e6%a1%88/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 03:47:03 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Microsoft Translator API]]></category>
		<category><![CDATA[properties]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=600</guid>
		<description><![CDATA[因為另外一套要錢，所以來用 Microsoft Translator API 隨手寫寫，一年沒寫文章，也許有點刻意，差不多該是改變的時候了。]]></description>
			<content:encoded><![CDATA[<p>因為另外一套要錢，所以來用 <a href="http://www.microsofttranslator.com/dev/">Microsoft Translator API</a></p>
<pre class="brush: python; title: ; notranslate">
#!/usr/bin/env python

# coding: utf-8

import urllib
import sys
import xml.dom.minidom

# Get Bing AppID from https://ssl.bing.com/webmaster/developers/appids.aspx
BING_APPID = 'KERO~'

FILE_FROM = 'lang.properties'
FILE_TO = 'translated.properties'

LANG_FROM = 'en'
LANG_TO = 'zh-chs'

def translate(text, from_lang, to_lang):
    base_url = 'http://api.microsofttranslator.com/v2/Http.svc/Translate?'
    data = urllib.urlencode({'appId':BING_APPID,
                             'from': from_lang.encode('utf-8'),
                             'to': to_lang.encode('utf-8'),
                             'text': text.encode('utf-8')
                            })

    url = base_url + data
    response = urllib.urlopen(url).read()

    dom = xml.dom.minidom.parseString(response)
    result = dom.documentElement.childNodes[0].nodeValue

    return result.encode('utf-8')

def parse_properties(filename):
    langs = {}
    with open(filename, 'r') as f:
        lines = [ line.strip() for line in f.readlines() ]
        for line in lines:
            idx = line.find('=')
            if idx == -1:
                continue

            (key, val) = (line[:idx], line[idx+1:])
            if not key:
                continue

            langs[key] = val

    return langs

def main():
    langs = parse_properties(FILE_FROM)
    translated = { k: translate(v, LANG_FROM, LANG_TO) if v else &quot;&quot;
                   for k,v in langs.items() }

    with open(FILE_TO, 'w+') as f:
        for k,v in sorted(translated.items()):
            f.write(&quot;%s=%s\n&quot; % (k,v))

if __name__ == '__main__':
    main()
</pre>
<p>隨手寫寫，一年沒寫文章，也許有點刻意，差不多該是改變的時候了。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2012/01/11/%e7%94%a8-microsoft-translatorapi-%e7%bf%bb%e8%ad%af-properties-%e6%aa%94%e6%a1%88/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>以 boost type traits 在 compile time 檢查 function 的 prototype</title>
		<link>http://blog.hubert.tw/2010/08/22/%e4%bb%a5-boost-type-traits-%e5%9c%a8-compile-time-%e6%aa%a2%e6%9f%a5-function-%e7%9a%84-prototype/</link>
		<comments>http://blog.hubert.tw/2010/08/22/%e4%bb%a5-boost-type-traits-%e5%9c%a8-compile-time-%e6%aa%a2%e6%9f%a5-function-%e7%9a%84-prototype/#comments</comments>
		<pubDate>Sun, 22 Aug 2010 14:19:51 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[boost]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=592</guid>
		<description><![CDATA[在使用 Google C++ Mocking Framework 的時候很可能遇到一個情況，當原本的 virtual function 的 prototype 改變的時候，你所 mocking 的 prototype 很可能不是預期會被呼叫的那個。 舉例來說 然而有一天，有一個新同事覺得他必須傳一個參數 int 進到 FuncB 當中，就直接對於宣告與實作動了手腳，所有的測試以及 production code 都沒有問題，直到跑了這個 unit test 才發現，原本預期被呼叫的 void (CA::*)() 沒有被呼叫，實際被呼叫的是 void (CA::*)(int) 這個版本。 那麼我們可不可以直接產生出 Google Mock Framework 所需的 function prototype &#8230; <a href="http://blog.hubert.tw/2010/08/22/%e4%bb%a5-boost-type-traits-%e5%9c%a8-compile-time-%e6%aa%a2%e6%9f%a5-function-%e7%9a%84-prototype/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>在使用 <a href="http://code.google.com/p/googlemock/">Google C++ Mocking Framework</a> 的時候很可能遇到一個情況，當原本的 virtual function 的 prototype 改變的時候，你所 mocking 的 prototype 很可能不是預期會被呼叫的那個。<br />
<span id="more-592"></span><br />
舉例來說</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;gmock /gmock.h&gt;
#include &lt;gtest /gtest.h&gt;

class CA
{
protected:
    virtual void FuncB() {
        std::cout &lt; &lt; &quot;CA FuncB&quot; &lt;&lt; std::endl;
    }

public:
    void FuncA() {
        FuncB();
    }
};

class CAOverrider: public CA
{
public:
    MOCK_METHOD0(FuncB, void());
};

void OverrideFuncB(){
    std::cout &lt;&lt; &quot;Override FuncB&quot; &lt;&lt; std::endl;
}

TEST(CATest, ExtractAndOverrideFuncB)
{
    using ::testing::Invoke;

    CAOverrider ca;
    EXPECT_CALL(ca, FuncB())
        .WillOnce(Invoke(OverrideFuncB));

    ca.FuncA();
}
</pre>
<p>然而有一天，有一個新同事覺得他必須傳一個參數 int 進到 FuncB 當中，就直接對於宣告與實作動了手腳，所有的測試以及 production code 都沒有問題，直到跑了這個 unit test 才發現，原本預期被呼叫的 void (CA::*)() 沒有被呼叫，實際被呼叫的是 void (CA::*)(int) 這個版本。</p>
<p>那麼我們可不可以直接產生出 Google Mock Framework 所需的 function prototype 呢？一開始的腦袋先動到 <a href="http://www.boost.org/doc/html/typeof/tuto.html">BOOST_TYPEOF</a> 這個 macro，不過我馬上意識到，這樣所產生出的型別是帶有 CA::* 這樣的 member pointer，與 Google C++ Mocking Framework 所需的並不相同。</p>
<p>在翻過一些文章之後，我發現過去曾經有人在 boost type traits 當中加入 <a href="https://svn.boost.org/trac/boost/browser/sandbox/type_traits/boost/type_traits/remove_member_pointer.hpp ">remove_member_pointer.hpp</a> 這個檔案</p>
<p>於是關鍵的那行就可以改成</p>
<pre class="brush: cpp; title: ; notranslate">
class CAOverrider: public CA
{
public:
    MOCK_METHOD0(FuncB,  boost::remove_member_pointer&lt;boost_typeof (&amp;CA::FuncB)&gt;::type);
};
</pre>
<p>如此一來就能夠在編譯的時期意識到這個問題了。</p>
<p>回到問題的本質上，這個問題起因於 MOCK_METHOD0 並沒有辦法明確指出他有 override CA 的 FuncB。這個問題似乎也在 C++0x 的 <a href="http://www.open-std.org/Jtc1/sc22/WG21/docs/papers/2009/n2928.htm">Explicit Virtual Overrides</a> 提出解法了。</p>
<p>我想這個解決方法並不是相當優雅，但也讓我開始意識到 C++ 的 template, type 以及 trait 的多樣性，也驅使我由這點再開始閱讀 Boost MPL，雖然現在才剛剛開始，但或許之後也慢慢會有不同的思維吧！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2010/08/22/%e4%bb%a5-boost-type-traits-%e5%9c%a8-compile-time-%e6%aa%a2%e6%9f%a5-function-%e7%9a%84-prototype/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Use VERSIONER_PYTHON_PREFER_32_BIT=yes in Snow Leopard</title>
		<link>http://blog.hubert.tw/2010/03/04/use-versioner_python_prefer_32_bityes-in-snow-leopard/</link>
		<comments>http://blog.hubert.tw/2010/03/04/use-versioner_python_prefer_32_bityes-in-snow-leopard/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 08:21:00 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA["Snow Leopard"]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[VERSIONER_PYTHON_PREFER_32_BIT]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=574</guid>
		<description><![CDATA[In python, you can use ctype (dl is deprecated now) to load dynamic link library. In 10.4 and 10.5 it may work fine, but it may occur errors in 10.6, such as /Library/Frameworks/dummy.framework/dummy: no matching architecture in universal wrapper Since &#8230; <a href="http://blog.hubert.tw/2010/03/04/use-versioner_python_prefer_32_bityes-in-snow-leopard/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In python, you can use <a href="http://docs.python.org/library/ctypes.html">ctype</a> (<a href="http://docs.python.org/library/dl.html">dl</a> is deprecated now) to load dynamic link library. In 10.4 and 10.5 it may work fine, but it may occur errors in 10.6, such as</p>
<blockquote><p>
/Library/Frameworks/dummy.framework/dummy: no matching architecture in universal wrapper
</p></blockquote>
<p>Since the python in Snow Leopard is 64-bit in default, for those libraries which does not support 64-bit. You can test your library by</p>
<blockquote><p>% file /Library/Frameworks/dummy.framework/Versions/Current/dummy
</p></blockquote>
<p>If you library is i386 only, you may need to handle it in this way.</p>
<blockquote><p>
% export VERSIONER_PYTHON_PREFER_32_BIT=yes<br />
% python your_script.py
</p></blockquote>
<p><a href="http://blog.ericsk.org/">ericsk</a> has also mentioned this for <a href="http://www.wxpython.org/">wxPython</a> in <a href="http://www.plurk.com/p/3zg4c0">his plurk</a></p>
<p>For more information, you can read the man page in your Snow Leopard.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2010/03/04/use-versioner_python_prefer_32_bityes-in-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using minimock for Python unit testing</title>
		<link>http://blog.hubert.tw/2010/02/24/using-minimock-for-python-unit-testing/</link>
		<comments>http://blog.hubert.tw/2010/02/24/using-minimock-for-python-unit-testing/#comments</comments>
		<pubDate>Wed, 24 Feb 2010 02:44:43 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA["unit test"]]></category>
		<category><![CDATA[minimock]]></category>
		<category><![CDATA[mock]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=568</guid>
		<description><![CDATA[我也忘了什麼時候開始習慣作 unit testing 了，可能是前一個專案在 Xcode 上就開始學著寫一點測試了。 這次在閱讀 Writing Testable Code 對於 6. Static methods: (or living in a procedural world)，格外有感覺。 尤其是修改別人的程式碼的時候，如果他總是直接呼叫 static method，不讓你用 mock object 把 implementation 換掉的話，這樣在測試起來就顯得麻煩的多。舉例來說，有一個 class method 會呼叫 SSHHelper.execute_ssh 這個指令去遠端執行一些東西，但這對 unit testing 而言就是一種外部的 dependency，你絕對不希望他真的在測試的時候跑出個 ssh 真的連過去執行些什麼吧。 剛好這次用 &#8230; <a href="http://blog.hubert.tw/2010/02/24/using-minimock-for-python-unit-testing/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>我也忘了什麼時候開始習慣作 unit testing 了，可能是前一個專案在 Xcode 上就開始學著寫一點測試了。</p>
<p>這次在閱讀 <a href="http://googletesting.blogspot.com/2008/08/by-miko-hevery-so-you-decided-to.html">Writing Testable Code</a> 對於 6. Static methods: (or living in a procedural world)，格外有感覺。</p>
<p>尤其是修改別人的程式碼的時候，如果他總是直接呼叫 static method，不讓你用 mock object 把 implementation 換掉的話，這樣在測試起來就顯得麻煩的多。舉例來說，有一個 class method 會呼叫 SSHHelper.execute_ssh 這個指令去遠端執行一些東西，但這對 unit testing 而言就是一種外部的 dependency，你絕對不希望他真的在測試的時候跑出個 ssh 真的連過去執行些什麼吧。</p>
<p>剛好這次用 <a href="http://pypi.python.org/pypi/MiniMock">MiniMock</a> 作我們的 mock library，因為他的因素，你就可以這樣作</p>
<pre class="brush: python; title: ; notranslate">
minimock.mock('SSHHelper.execute_ssh', returns=ssh_output)
</pre>
<p>如此一來，execute_ssh 這個 method 的結果就可以簡單的換成你預期的 ssh_output。</p>
<p>如果是本來就有比較好的設計的話，你也可以用 minimock.Mock (注意大小寫)，去產生一個 mock object 出來。</p>
<pre class="brush: python; title: ; notranslate">
mock_fs = minimock.Mock('MockFileSystem')
mock_fs.size.mock_returns = 1
mytools.fs_imp = mock_fs
</pre>
<p>如此一來 mock 就顯得簡單多了……</p>
<p>話說回來，之前想寫的 objective-c 跟 DTrace 的 topic 真的都忘的差不多了，算了，以後再說吧，也許之後把 python 的 <a href="http://www.python.org/dev/peps/pep-3134/">Exception Chaining and Embedded Tracebacks</a> 的想法整理一下再丟出來吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2010/02/24/using-minimock-for-python-unit-testing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一個 boost::exception 的例子</title>
		<link>http://blog.hubert.tw/2009/07/08/%e4%b8%80%e5%80%8b-boostexception-%e7%9a%84%e4%be%8b%e5%ad%90/</link>
		<comments>http://blog.hubert.tw/2009/07/08/%e4%b8%80%e5%80%8b-boostexception-%e7%9a%84%e4%be%8b%e5%ad%90/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 17:05:57 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[boost::exception]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=535</guid>
		<description><![CDATA[因為覺得 dprintf 出現的次數實在太多了，我會希望在 exception 就可以包好 __FILE__ 跟 __LINE__，又可以把 std::wstring 包在 exception 一起丟出去，在 catch 的時候再印出來就好。 所以試著寫了這樣一個例子，結果寫的四不像，跟原本想的東西完全部不同了，而且我對於那個 BUFSIZ 相當不滿啊。其實原本希望可以用 ##__VA_ARGS__ 這種 macro 直接吃進來變成一個 boost::any[]，然後再想辦法轉成 boost::format 可以用的格式，中間還可以透過 BOOST_FOREACH 來玩的，不過我徹底失敗了，所以最後的成果大家笑笑就好了。 然後關於 boost::any 的 construct 不能吃 const char * 的事情，其實不用改到 boost::any 的 source code，稍微這樣惡搞一下就可以了。 不過我大概要好一段時間碰不到 &#8230; <a href="http://blog.hubert.tw/2009/07/08/%e4%b8%80%e5%80%8b-boostexception-%e7%9a%84%e4%be%8b%e5%ad%90/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>因為覺得 dprintf 出現的次數實在太多了，我會希望在 exception 就可以包好 __FILE__ 跟 __LINE__，又可以把 std::wstring 包在 exception 一起丟出去，在 catch 的時候再印出來就好。</p>
<p>所以試著寫了這樣一個例子，結果寫的四不像，跟原本想的東西完全部不同了，而且我對於那個 BUFSIZ 相當不滿啊。其實原本希望可以用 ##__VA_ARGS__ 這種 macro 直接吃進來變成一個 boost::any[]，然後再想辦法轉成 boost::format 可以用的格式，中間還可以透過 BOOST_FOREACH 來玩的，不過我徹底失敗了，所以最後的成果大家笑笑就好了。<span id="more-535"></span></p>
<pre class="brush: cpp; title: ; notranslate">
#define BOOST_THROW_EXCEPTION_STRING(fmt, ...)\
    do {\
        BOOST_THROW_EXCEPTION(an_exception() &lt;&lt; throw_wstring(valistToStr(fmt, ##__VA_ARGS__)));\
        \
    } while(0)

inline std::wstring valistToStr(const wchar_t *fmt, ...)
{
    wchar_t wszMessage[BUFSIZ] = {0};

    va_list ap;
    va_start(ap, fmt);
    vswprintf(wszMessage, sizeof(wszMessage)/sizeof(wszMessage[0]) - 1, fmt, ap);
    va_end(ap);

    return std::wstring(wszMessage);
}

typedef boost::error_info&lt; struct tag_throw_wstring, std::wstring &gt; throw_wstring;
struct an_exception : public boost::exception, public std::exception {};

int main(int argc, wchar_t *argv[])
{
    try
    {
        BOOST_THROW_EXCEPTION_STRING( L&quot;%S%d&quot;, L&quot;lala&quot;, 1);
    }
    catch(boost::exception&amp; e)
    {
        boost::wformat fmt(L&quot;[%S] %S - [%S(%d)]&quot;);
        std::wstring wstrError = boost::str(fmt %
                *boost::get_error_info&lt;boost::throw_function&gt;(e) %
                boost::get_error_info&lt;throw_wstring&gt;(e)-&gt;c_str() %
                *boost::get_error_info&lt;boost::throw_file&gt;(e) %
                *boost::get_error_info&lt;boost::throw_line&gt;(e)
        );

        std::wcout &lt;&lt; wstrError &lt;&lt; std::endl;
    }

    return 0;
}
</pre>
<p>然後關於 boost::any 的 construct 不能吃 const char * 的事情，其實不用改到 boost::any 的 source code，稍微這樣惡搞一下就可以了。</p>
<pre class="brush: cpp; title: ; notranslate">
class my_any : public boost::any
{
public:
    template&lt;typename ValueType&gt;
    my_any(const ValueType &amp; value)
    {
        typename boost::decay&lt;const ValueType&gt;::type t = value;
        boost::any a(t);
        this-&gt;swap(a);
    }
};
</pre>
<p>不過我大概要好一段時間碰不到 C++ 了，可能有幾個月要轉換開發平台了（默）</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2009/07/08/%e4%b8%80%e5%80%8b-boostexception-%e7%9a%84%e4%be%8b%e5%ad%90/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>從 inet_ntoa 看 thread safe 的 API</title>
		<link>http://blog.hubert.tw/2009/04/18/%e5%be%9e-inet_ntoa-%e7%9c%8b-thread-safe-%e7%9a%84-api/</link>
		<comments>http://blog.hubert.tw/2009/04/18/%e5%be%9e-inet_ntoa-%e7%9c%8b-thread-safe-%e7%9a%84-api/#comments</comments>
		<pubDate>Sat, 18 Apr 2009 13:35:59 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[thread safe]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=522</guid>
		<description><![CDATA[這周 refactor 一段 code 之後，被同事說：「為什麼 log 的來源 IP 跟目的地 IP 總是一樣呢？」 後來仔細想了一下 inet_ntoa 的 prototype，我就明白了！如果這個 function 不必特意去 free 回傳的 pointer，那可能在內部有一個 static buffer 去保存這個值。果不期然，FreeBSD 的原始碼是這樣實作的 到這邊我們大概就知道，inet_ntoa 並不是一個 thread safe 的 function，你可以用下面這段程式測一下會發生什麼事情。 輸出大概會像 127.0.0.2 => 127.0.0.1 127.0.0.1 => 127.0.0.2 127.0.0.1 => [inet_ntoa &#8230; <a href="http://blog.hubert.tw/2009/04/18/%e5%be%9e-inet_ntoa-%e7%9c%8b-thread-safe-%e7%9a%84-api/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>這周 refactor 一段 code 之後，被同事說：「為什麼 log 的來源 IP 跟目的地 IP 總是一樣呢？」</p>
<pre class="brush: cpp; title: ; notranslate">
char *szDestIp = inet_ntoa(destAddr);
char *szSrcIp = inet_ntoa(srcAddr);
</pre>
<p>後來仔細想了一下 inet_ntoa 的 prototype，我就明白了！如果這個 function 不必特意去 free 回傳的 pointer，那可能在內部有一個 static buffer 去保存這個值。果不期然，FreeBSD 的原始碼是這樣實作的</p>
<pre class="brush: cpp; title: ; notranslate">
/*const*/ char *
inet_ntoa(struct in_addr in) {
        static char ret[18];

        strcpy(ret, &quot;[inet_ntoa error]&quot;);
        (void) inet_ntop(AF_INET, &amp;in, ret, sizeof ret);
        return (ret);
}

char *
inet_ntoa_r(struct in_addr in, char *buf, socklen_t size)
{
        (void) inet_ntop(AF_INET, &amp;in, buf, size);
        return (buf);
}
</pre>
<p>到這邊我們大概就知道，inet_ntoa 並不是一個 thread safe 的 function，你可以用下面這段程式測一下會發生什麼事情。</p>
<pre class="brush: cpp; title: ; notranslate">
void* thread_func (void *param)
{
    char * addr= (char *)param;
    struct in_addr val;
    inet_aton(addr, &amp;val);

    while (1)
        printf(&quot;%s =&gt; %s\n&quot;, addr, inet_ntoa(val));

    pthread_exit(NULL);
}

int main()
{
    pthread_t thr1, thr2;
    pthread_create(&amp;thr1, NULL, thread_func, (void *)&quot;127.0.0.1&quot;);
    pthread_create(&amp;thr2, NULL, thread_func, (void *)&quot;127.0.0.2&quot;);

    while(1) {
        sleep (1);
    }

    return 0;
}
</pre>
<p>輸出大概會像</p>
<blockquote><p>
127.0.0.2 => 127.0.0.1<br />
127.0.0.1 => 127.0.0.2<br />
127.0.0.1 => [inet_ntoa error]<br />
127.0.0.2 => 127.0.0.2
</p></blockquote>
<p>所以，直接使用 inet_ntoa 在 reentrant 上可能會發生問題，如果你必須面對這些問題，最好的方式就是使用 inet_ntoa_r 這個 reentrant 的版本，或者直接使用 inet_ntop。</p>
<p>而這難道非得要踩到地雷，或者從 API 的細節才能窺知這一切嗎？其實並不完全是，當你發現回傳的是一個 char *，又沒有要求你特別 free 他，你是不是就該猜測他是回傳 function 內部的一個 static buffer 了呢？所以，舉凡 ctime, asctime 都不保證是 thread safe 的，這是我們 programmer 該留意的細節。</p>
<p>所以，也許我們以後需要更小心的去寫程式，在選擇 API 時也必須留意更多細節，以免未來踩到更多地雷……。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2009/04/18/%e5%be%9e-inet_ntoa-%e7%9c%8b-thread-safe-%e7%9a%84-api/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>以 boost::posix_time 處理時間字串</title>
		<link>http://blog.hubert.tw/2009/03/29/%e4%bb%a5-boostposix_time-%e8%99%95%e7%90%86%e6%99%82%e9%96%93%e5%ad%97%e4%b8%b2/</link>
		<comments>http://blog.hubert.tw/2009/03/29/%e4%bb%a5-boostposix_time-%e8%99%95%e7%90%86%e6%99%82%e9%96%93%e5%ad%97%e4%b8%b2/#comments</comments>
		<pubDate>Sat, 28 Mar 2009 16:41:09 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[posix_time]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=510</guid>
		<description><![CDATA[其實標題並不是那麼準確，這點我們之後再談。 其實起源很簡單，我們常常需要從各式各樣的時間字串轉成 time_t 或者 struct tm，要不然還可能是 FILETIME 跟 SYSTEMTIME 之類的結構。個人覺得 parsing 時間是一件難搞的事情，尤其是當你還要考慮 timezone 的影響，一切都變得不是那麼簡單了。 首先我必須要說，在 Windows 中沒有 strptime(3) 這樣還算好用的東西可以用，所以我又把腦袋動到 boost 上面去了。 我的目標是正確的處理「Sat, 28 Mar 2009 20:18:32 +0800」這樣的字串，然後把他轉成 time_t。我們會分兩個部份處理，首先我們先處理「Sat, 28 Mar 2009 20:18:32」這個部份，因為目前的 %q 只能處理輸出部份，請參考 Date Time Formatter/Parser Objects。 這樣的確很簡單吧，只要按照文件寫的把 format &#8230; <a href="http://blog.hubert.tw/2009/03/29/%e4%bb%a5-boostposix_time-%e8%99%95%e7%90%86%e6%99%82%e9%96%93%e5%ad%97%e4%b8%b2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>其實標題並不是那麼準確，這點我們之後再談。</p>
<p>其實起源很簡單，我們常常需要從各式各樣的時間字串轉成 time_t 或者 struct tm，要不然還可能是 FILETIME 跟 SYSTEMTIME 之類的結構。個人覺得 parsing 時間是一件難搞的事情，尤其是當你還要考慮 timezone 的影響，一切都變得不是那麼簡單了。</p>
<p>首先我必須要說，在 Windows 中沒有 <a href="http://www.freebsd.org/cgi/man.cgi?query=strptime&#038;sektion=3">strptime(3)</a> 這樣還算好用的東西可以用，所以我又把腦袋動到 boost 上面去了。</p>
<p>我的目標是正確的處理「Sat, 28 Mar 2009 20:18:32 +0800」這樣的字串，然後把他轉成 time_t。我們會分兩個部份處理，首先我們先處理「Sat, 28 Mar 2009 20:18:32」這個部份，因為目前的 %q 只能處理輸出部份，請參考 <a href="http://www.boost.org/doc/libs/1_38_0/doc/html/date_time/date_time_io.html#date_time.io_objects">Date Time Formatter/Parser Objects</a>。</p>
<pre class="brush: cpp; title: ; notranslate">
    using namespace boost::posix_time;
    using namespace boost;
    using namespace std;

    std::string strDateTime = &quot;Sat, 28 Mar 2009 20:18:32 +0800&quot;;
    std::string format = &quot;%a, %d %b %Y %H:%M:%S&quot;;

    ptime pt(not_a_date_time);

    time_input_facet * input_facet = new time_input_facet(format);

    stringstream ss(strDateTime);
    ss.imbue(locale(ss.getloc(), input_facet ));

    ss &gt;&gt; pt;
</pre>
<p>這樣的確很簡單吧，只要按照文件寫的把 format 寫好，boost 就能幫你從 stringstream 的字串轉成 posix_time。</p>
<p>而 timezone 的部份就需要噁心一點的作法了。</p>
<pre class="brush: cpp; title: ; notranslate">
    std::string strHour, strMinute;
    ss &gt;&gt; setw(3) &gt;&gt; strHour &gt;&gt; setw(2) &gt;&gt; strMinute;

    time_duration td(lexical_cast&lt; int &gt;(strHour), lexical_cast &lt; int &gt; (strMinute), 0);
    pt -= td;
</pre>
<p>我利用 setw 分別把 timezone 的小時與分抓出來，並轉成 time_duration，讓 posix_time 能直接減掉 timezone 的 offset 成為 GMT time，之後再做點手腳就可以變成 time_t 了。</p>
<p>嚴格來說，我想我是透過 time_input_facet 來處理字串的，希望這點小技巧對於需要 parsing 時間字串的人能有所幫助。</p>
<p>p.s: 其實這篇三個禮拜前就準備好了，只是一直拖到現在才把他丟出來 XD</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2009/03/29/%e4%bb%a5-boostposix_time-%e8%99%95%e7%90%86%e6%99%82%e9%96%93%e5%ad%97%e4%b8%b2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>初探 TR1 function object</title>
		<link>http://blog.hubert.tw/2009/01/13/%e5%88%9d%e6%8e%a2-tr1-function-object/</link>
		<comments>http://blog.hubert.tw/2009/01/13/%e5%88%9d%e6%8e%a2-tr1-function-object/#comments</comments>
		<pubDate>Tue, 13 Jan 2009 12:37:04 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[tr1]]></category>
		<category><![CDATA[tr1::bind]]></category>
		<category><![CDATA[tr1::function]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=418</guid>
		<description><![CDATA[最近的專案常常需要更新 INI 設定檔，而最麻煩的事情莫過於太多零散的設定，你必須要記住 INI 檔設定的 key，再把在某個 object 的 member function 把值抓出來，最後再丟給 WritePrivateProfileString 之類的 function 把值更新進檔案。 所以常常就會寫出一堆噁心的 code 像是。 obj.iniKey = "INI_SERVER"; obj.iniValue = info.GetServer(); UpdateByObj(obj); 這樣的話，有幾個設定就要寫幾次，所有的 Key 跟 Value 的相關性都顯得零散，未來要加上新的設定，也非得要再加上類似的 code 才行……。 忽然我就靈機一動，也許可以用 tr1::function 跟 tr1::bind 來做這樣的事情。 struct proxyConfig { &#8230; <a href="http://blog.hubert.tw/2009/01/13/%e5%88%9d%e6%8e%a2-tr1-function-object/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>最近的專案常常需要更新 INI 設定檔，而最麻煩的事情莫過於太多零散的設定，你必須要記住 INI 檔設定的 key，再把在某個 object 的 member function 把值抓出來，最後再丟給 WritePrivateProfileString 之類的 function 把值更新進檔案。</p>
<p>所以常常就會寫出一堆噁心的 code 像是。</p>
<pre class="php-codeface">
    obj.iniKey = "INI_SERVER";
    obj.iniValue = info.GetServer();
    UpdateByObj(obj);
</pre>
<p>這樣的話，有幾個設定就要寫幾次，所有的 Key 跟 Value 的相關性都顯得零散，未來要加上新的設定，也非得要再加上類似的 code 才行……。</p>
<p>忽然我就靈機一動，也許可以用 tr1::function 跟 tr1::bind 來做這樣的事情。</p>
<pre class="php-codeface">
    struct proxyConfig
    {
        std::string iniKey;
        std::tr1::function&lt;std::string()&gt; func;
    };

    const proxyConfig configArray [] =
    {
        { "INI_SERVER", std::tr1::bind(&#038;proxyInfo::GetServer, &#038;info) },
        { "INI_PORT",   std::tr1::bind(&#038;proxyInfo::GetPort, &#038;info) },
        { "INI_USER",   std::tr1::bind(&#038;proxyInfo::GetUser, &#038;info) },
        { "INI_PASS",   std::tr1::bind(&#038;proxyInfo::GetPass, &#038;info) },
    };

    for (size_t i = 0; i < sizeof(configArray)/sizeof(configArray[0]); ++i)
    {
        obj.iniKey = configArray[i].iniKey;
        obj.iniValue = configArray[i].func();
        UpdateByObj(obj);
    }
</pre>
<p>靠著把 INI 的 key 跟 member function 建表就顯得簡單一點，並把更新的程式碼簡化成一份，未來如果要新增不同的設定，也只要更動表中的 INI key 跟所綁定的 function 就好。</p>
<p>不過後來仔細想想，其實只要在建表的時候寫成 info.GetServer() 就可以滿足我的需求了。</p>
<p>而 tr1::function 與 tr1::bind 絕對不是只有這點小技倆而已，真正使用的巧妙應該是 <a href="http://www.ddj.com/cpp/184401949">C++ Function Objects in TR1</a> 所提及那種彈性而優雅地將 function 包裹成物件，能有改變的彈性，也能應時應地做出適合的調整。</p>
<p>如果你的編譯器還不支援 tr1，除了換一個之外，你還可以考慮一下 <a href="http://www.boost.org/">boost</a>，也許更瞭解一點，會讓你的生活變得更好歐。</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2009/01/13/%e5%88%9d%e6%8e%a2-tr1-function-object/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++ Format String using boost::format</title>
		<link>http://blog.hubert.tw/2009/01/03/c-format-string-using-boostformat/</link>
		<comments>http://blog.hubert.tw/2009/01/03/c-format-string-using-boostformat/#comments</comments>
		<pubDate>Sat, 03 Jan 2009 12:59:34 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[boost]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=409</guid>
		<description><![CDATA[如果你只想寫純粹的 C，那你可以忽略這篇的資訊了，因為 sprintf 之類的 function 大概就可以滿足你了。那為什麼還要提到 C++？我想 C++ 的 string 對於程式設計者是美好的，因為我們不用擔心 buffer 到底需要多長，我們可能是無腦的利用 operator += 去操作這個字串，並利用提供的 substring 等 function 快速的開發軟體。 但在我甚少的 C++ 開發經驗中，我總覺得透過 operator += 以及 stringstream 等東西，並沒有辦法像 sprintf 那樣直覺而優雅的將變數置換至字串當中。 就以 Windows 常見的 INI 格式來說，我們如果要輸出一個 AppName，像是 [MyApp]，可能的作法是 這似乎比傳統的 sprintf 要顯得複雜的多，也顯得不好閱讀…… &#8230; <a href="http://blog.hubert.tw/2009/01/03/c-format-string-using-boostformat/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>如果你只想寫純粹的 C，那你可以忽略這篇的資訊了，因為 sprintf 之類的 function 大概就可以滿足你了。那為什麼還要提到 C++？我想 C++ 的 string 對於程式設計者是美好的，因為我們不用擔心 buffer 到底需要多長，我們可能是無腦的利用 operator += 去操作這個字串，並利用提供的 substring 等 function 快速的開發軟體。</p>
<p>但在我甚少的 C++ 開發經驗中，我總覺得透過 operator += 以及 stringstream 等東西，並沒有辦法像 sprintf 那樣直覺而優雅的將變數置換至字串當中。</p>
<p>就以 Windows 常見的 INI 格式來說，我們如果要輸出一個 AppName，像是 [MyApp]，可能的作法是</p>
<pre class="brush: cpp; title: ; notranslate">
    output += '[';
    output += strSection;
    output += ']';
</pre>
<p>這似乎比傳統的 sprintf 要顯得複雜的多，也顯得不好閱讀……</p>
<pre class="brush: css; title: ; notranslate">
    sprintf(output, &quot;[%s]&quot;, strSection);
</pre>
<p>現在你可以考慮 <a href="http://www.boost.org/doc/libs/1_37_0/libs/format/doc/format.html">boost::format</a></p>
<pre class="brush: cpp; title: ; notranslate">
    std::string output = boost::str(boost::format(&quot;[%s]&quot;) % strSection);
</pre>
<p>讓你寫的 C++ 能有 sprintf 的優雅性，又不必太過於擔心 buffer 的操作。</p>
<p>至於一些 manipulators，與詳細的 formatting 的用法，就請你自己去看一下官方的說明吧。此外，我覺得 python 的 formatting string 能吃 dictionary 也實在是很棒，而且很優雅的寫法。</p>
<pre class="brush: python; title: ; notranslate">
    print &quot;%(key)s %(key)s&quot; % {'key': 'yoyo'}
</pre>
<p>在 boost::format 雖然只能這樣寫，但也聊勝於無了。</p>
<pre class="brush: cpp; title: ; notranslate">
    std::cout &lt; &lt; boost::format(&quot;%1% %1%&quot;) % &quot;yoyo&quot;;
</pre>
<p>某些情況下，你會考慮用 boost::lexical_cast，而捨棄 stringstream 等，不過也容許我提醒你一下，boost 會讓 object 變得肥上不少，至於怎麼取捨，就端看你的選擇了。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2009/01/03/c-format-string-using-boostformat/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>使用 sysexits.h 定義的 EX_ 變數</title>
		<link>http://blog.hubert.tw/2008/08/20/%e4%bd%bf%e7%94%a8-sysexitsh-%e5%ae%9a%e7%be%a9%e7%9a%84-ex_-%e8%ae%8a%e6%95%b8/</link>
		<comments>http://blog.hubert.tw/2008/08/20/%e4%bd%bf%e7%94%a8-sysexitsh-%e5%ae%9a%e7%be%a9%e7%9a%84-ex_-%e8%ae%8a%e6%95%b8/#comments</comments>
		<pubDate>Wed, 20 Aug 2008 07:46:26 +0000</pubDate>
		<dc:creator>Hubert</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[exit]]></category>
		<category><![CDATA[sysexits]]></category>

		<guid isPermaLink="false">http://blog.hubert.tw/?p=304</guid>
		<description><![CDATA[以前我們常常在程式裡面直接呼叫 exit, 並搭配一個自己「想要」的變數作為程式的 return code，像是 這樣的壞處是，我們不知道 0 代表什麼，-1 又代表什麼，這樣一來可讀性也會顯得比較差了一點。今天在無意之間看到 FreeBSD 的 lockf，他使用了 sysexits(3)，在這邊節錄一下 man page 的敘述。 According to style(9), it is not a good practice to call exit(3) with arbitrary values to indicate a failure condition when ending a program. &#8230; <a href="http://blog.hubert.tw/2008/08/20/%e4%bd%bf%e7%94%a8-sysexitsh-%e5%ae%9a%e7%be%a9%e7%9a%84-ex_-%e8%ae%8a%e6%95%b8/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>以前我們常常在程式裡面直接呼叫 exit, 並搭配一個自己「想要」的變數作為程式的 return code，像是</p>
<pre class="brush: cpp; title: ; notranslate">
exit(-1)
</pre>
<p>這樣的壞處是，我們不知道 0 代表什麼，-1 又代表什麼，這樣一來可讀性也會顯得比較差了一點。今天在無意之間看到 FreeBSD 的 lockf，他使用了 sysexits(3)，在這邊節錄一下 man page 的敘述。</p>
<blockquote><p>
     According to style(9), it is not a good practice to call exit(3) with<br />
     arbitrary values to indicate a failure condition when ending a program.<br />
     Instead, the pre-defined exit codes from sysexits should be used, so the<br />
     caller of the process can get a rough estimation about the failure class<br />
     without looking up the source code.
</p></blockquote>
<p>現在你可以改呼叫 </p>
<pre class="brush: cpp; title: ; notranslate">
exit(EX_USAGE)
</pre>
<p>這樣是不是好讀的多呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hubert.tw/2008/08/20/%e4%bd%bf%e7%94%a8-sysexitsh-%e5%ae%9a%e7%be%a9%e7%9a%84-ex_-%e8%ae%8a%e6%95%b8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

