melt日記

.NETすらまともに扱えないへたれのページ

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  111  : 記事  3  : コメント  8268  : トラックバック  41

ニュース

わんくま同盟

わんくま同盟

C# と VB.NET の質問掲示板

iKnow!


Dictation



書庫

2008年5月22日 #

ATL には、A2T だの CA2CT だのといった文字列変換マクロがあります。


ここを見れば分かるのですが、これらのマクロは時代によっていくつかの種類に分かれていたようで、最初に使われていたのは A2T だの A2W といったマクロのようです。

void foo(const char* p)
{
    USES_CONVERSION;
    TCHAR* pStr = A2T(p);
    ...
}

しかしこれは _alloca() を使っているため、下手をするとスタックオーバーフローを起こす危険性があったようです。


そこで作られたのが CA2T や CA2W といった、先頭に C の付いたマクロです。

これは固定サイズの配列をローカル変数として取っておき、そこに文字列を格納します。

もしローカルの配列に収まらなかった場合はヒープから領域を確保して、そこに文字列を格納します。

void foo(const char* p)
{
    CA2T pStr(p);
    ...
}

これなら _alloca() を使っていないので、普通にローカル変数を定義するのと同じ程度しかスタックを消費しません。


しかし、上記2つのコードを見れば分かるのですが、これらは機械的に置き換えられるものではなく、内容を精査した上で置き換える必要があります。

古くから使われている A2T 等のマクロが1万件とかある場合、さすがに手動で置き換える気はしません。


そこで使えるのが _EX とついたマクロ群。

これらを使えば、最初の例は以下のように置き換えることが出来ます。

void foo(const char* p)
{
    USES_CONVERSION_EX;
    TCHAR* pStr = A2T_EX_DEF(p);
}

USES_CONVERSION は USES_CONVERSION_EX に、A2T は A2T_EX_DEF に変更するだけです。

A2T_EX_DEF というのはどういう動作になるかというと、内部的には _ATL_SAFE_ALLOCA を使っているので、ある程度のサイズ(デフォルトは 1024 バイト)までは _alloca() によって確保しようとして、それ以上になるとヒープから確保します。

また、1024 バイト以下であっても _alloca() によってスタックオーバーフローが起きてしまう場合、ヒープから確保してくれます。


A2T や A2W だとスタックオーバーフローが起きてしまうから使ってはダメ!と言われたけれども件数が多くて手動で直すのが非常に面倒な場合は、このマクロが使えそうな気がします。

posted @ 10:53 | Feedback (279)