マクロで動的変数名の生成

マクロ __LINE__ を、変数名の一部として使用できるかを検証した時のメモです。

まず初めに、例えばwhile文にタイムアウトを持たせたマクロを以下のよう書いてみたとします。
#define  while_timeout(t)  for(DWORD dwStartTime = GetTickCount(); GetTickCount() - dwStartTime < (t);)

こんな感じで使います。
BOOL func()
{
    while_timeout(2000)
    {
        if( 何かチェック )
            return TRUE;
    }
    
    return FALSE;
}

このマクロ、マクロ内で変数 dwStartTime を定義しているため、同スコープ内で2回以上使用すると、
error C2374: 'dwStartTime' : 再定義されています。2 回以上初期化されています。
'dwStartTime' の宣言を確認してください。
というエラーになってしまいます。

while_timeout文の前後を {} で括ってもよいのですが、ソースの可読性が損なわれてしまいます。
以下のようにすれば、dwStartTime部分の変数名を、__LINE__を使用した行ごとに異なる変数名にすることができます。
#define  while_timeout__(t, l)  for(DWORD dw##l = GetTickCount(); GetTickCount() - dw##l < (t);)
#define  while_timeout_(t, l)   while_timeout__(t, l)
#define  while_timeout(t)       while_timeout_(t, __LINE__)
__LINE__の置換よりもトークン連結(##)の優先順位が高いためでしょうか、上記のように while_timeout_ マクロを1段階通さないと dw と __LINE__ が上手く連結されません(dw と __LINE__ が先に連結され、dw__LINE__という変数名になってしまいます)。

また、VC++ 6 ではコンパイルオプションに /ZI がある場合はコンパイルできませんでした、なんでしょこれ。。


2008.04.30

ETCトップへ