Andante

Home / tips

Tips集

目次

C/C++

コメントスイッチ

一時的なテストコードを瞬時に切り替えたいなんて時はこれ↓

/**
    { int tmp = a; a = b;  b = tmp; }
/*/
    a ^= b ^= a ^= b;
/**/

切り替えるには、最初の /** に / を足してやればOK。

/**/
    { int tmp = a; a = b; b = tmp; }
/*/
    a ^= b ^= a ^= b;
/**/

#if 〜 #else 〜 #endif で切り替えると色が変わらない (VC++2005 ではプリプロセッサの色分けしてくれますが、更新が遅い) からどっちが実行されるコードなのかひと目では分かりにくいので、 コメントにしてやればもう一目瞭然!…ってなわけで、いかが?

#if と違ってネストできませんが、こういうものはネストすべきじゃないと思うので、要らんでしょう。。

目次へ

VC++のforスコープ抜け対策

for (int i = 0; i < 10; i++) {
    ...
}
a = i; // for 内で宣言した i がスコープ抜けても生きてる。。(~Д~;

という、VC++(2005以前) のバグ対策には、

#ifndef for
#define for if (0) ; else for
#endif

というヘンテコなマクロで解決!

VC++以外のコンパイラに通しても無害なので、いつもファイル先頭に書いておけば安心。

要は if (1) for 〜 みたいにしてやれば、for はダメでも if がスコープを閉じてくれるので、 あたかも for で閉じてるように見せかけることができるわけです。で、上のような形をしているのは、 if (1) for だと、間違って for (〜) {〜} else {〜} のように書いてもコンパイルエラーにならないので、 それを回避するためです。どっちにせよ、if (0) ; else なんてものはコンパイラが不要と判断して削除するので、 アセンブラに落ちるコードは変わりません。

目次へ

多次元配列の動的確保

たとえば、int a[3][4]; のような多次元配列を動的に確保するには、

int **a;
int i;
a = (int **)malloc(sizeof(int *) * 3);
for (i = 0; i < 3; i++)
    a[i] = (int *)malloc(sizeof(int) * 4);

として、解放は

int i;
for (i = 0; i < 3; i++)
    free(a[i]);
free(a);

とするのが一般的ですが、解放に手間がかかるので、ちょっと一工夫↓

int **a;
int i;
a = (int **)malloc(sizeof(int *) * 3 + sizeof(int) * 3 * 4);
for (i = 0; i < 3; i++)
    a[i] = (int *)(a + 3) + 4 * i;

こうすれば1回の free() で一気に全て解放できるという仕掛けです。 → ライブラリ作ってみました。

目次へ

関数ネスト (C++)

「関数内で何回もやる処理はまとめたいけど、他で使わないのにファイルスコープな関数は作りたくない。」

「作るにしても、ローカル変数いぢるためにそれ全部引数に書くなんてめんどくさいし保守タイヘン。」

とまあ、これらを解決するにはDみたいにネスト関数がネイティブにサポートされていれば無問題なんですが、 あいにくC++にはネスト関数がありません。じゃあ作ったろうじゃないの!ということで作ってみました。

#define nestfn_bgn(type, func, args) \
    struct nestfn__##func \
    { \
        static type func args \
        {
#define nestfn_end(type, func, args) \
        }; \
    }; \
    static type (*func) args = nestfn__##func::func;

#include <iostream>

void main()
{
    // int add(int a, int b)
    // {
    //     return a + b;
    // }
    nestfn_bgn(int, add, (int a, int b))
    {
        return a + b;
    }
    nestfn_end(int, add, (int a, int b))
    
    std::cout << add(1, 2) << std::endl; // 3
}

ただ、1つ注意点があります。

(ネスト親の)ローカル変数は static じゃないとアクセスできない!

int foo()
{
    static int a;
           int b;
    
    nestfn_bgn(int, get_a, ())
    {
        return a; // OK
    }
    nestfn_end(int, get_a, ())
    
    nestfn_bgn(int, get_b, ())
    {
        return b; // NG コンパイルエラー
    }
    nestfn_end(int, get_b, ())
    
    a = 1;
    return get_a();
}

auto な class とかは結局引数で渡すしかないのね…。

目次へ

Copyright (C) MALU 2008