#pragma twice

KAB-studio > プログラミング > #pragma twice > 214 Version 11.14 メモリ確保とデバッグモード

#pragma twice 214 Version 11.14 メモリ確保とデバッグモード

前のページへ 表紙・目次へ 次のページへ

 Version 11.14
メモリ確保とデバッグモード

今回は、前回触れた _malloc_dbg() について解説します
 malloc() のデバッグモード版だよね
一応そういうことになるかな
あ、 malloc() 呼んでても、デバッグモードだと _malloc_dbg() が呼ば
れるから
正確にはちょっと違うってことになるね。じゃ、まずは使ってみようか

void Use_malloc_dbg()
{
    // このデータが入る領域を確保します。
    const char *const DATA = "あいうえお";

    // まず確保。
    char *pch
        = (char *)_malloc_dbg
            ( strlen( DATA ) + 1 
            , _NORMAL_BLOCK
            , __FILE__
            , __LINE__
            );

    // コピーしてから出力。
    strcpy( pch, DATA );
    TRACE( "%s\n", pch );

    // 解放します。
    _free_dbg( pch, _NORMAL_BLOCK );
}

普通の malloc() よりも引数多いね
 malloc() よりも機能が多いからね。ひとつひとつ引数を見ていこうか

    char *pch
        = (char *)_malloc_dbg
            ( strlen( DATA ) + 1 
            , _NORMAL_BLOCK
            , __FILE__
            , __LINE__
            );

1番目の引数はおなじみのサイズだね。2番目の _NORMAL_BLOCK は?
どの部分のメモリを確保するか指定するフラグだね。これはあとで呼ぶ 
_free_dbg() と統一してあれば大丈夫かな
あ、 free() も専用のなんだね
第3引数と第4引数はマクロ。これは C++ 言語そのものが持ってる特殊
なマクロで、 __FILE__ はファイル名、 __LINE__ は行番号に置き換わりま

???
簡単に試してみようか

void Use_FILE_LINE()
{
    TRACE( "%s\n", __FILE__ );
    // C:\Program\StringTest\StringTestDlg.cpp
    TRACE( "%d\n", __LINE__ );
    // 122
}

この関数の置き場所が StringTestDlg.cpp の 118 行目ならこんなふうに
なるはず
んー……
つまり、コンパイルするときにプログラムの中に __FILE__ や __LINE__ 
を見つけたら

    TRACE( "%s\n", "C:\Program\StringTest\StringTestDlg.cpp" );
    // C:\Program\StringTest\StringTestDlg.cpp
    TRACE( "%d\n", 122 );
    // 122

に置き換えられて、それからコンパイルされるんです
あ、そっか、マクロだから置き換わるんだ。それが……
 __FILE__ だったら __FILE__ が書かれているファイルのフルパス、 
__LINE__ だったら __LINE__ が書かれてる行の行数に置き換わるってこ

さっきのも置き換わるんだ。でも、これが何に使われるの?
たとえば、さっきの Use_malloc_dbg() で、 _free_dbg() の行をコメン
トアウトしてみて
そんなことしたらメモリリークするんじゃない?
わざとさせてみるの
あー。ほい

Detected memory leaks!
Dumping objects ->
C:\Program\StringTest\StringTestDlg.cpp(127) : 
{68} normal block at 0x00421690, 11 bytes long.
 Data: <           > 82 A0 82 A2 82 A4 82 A6 82 A8 00 
Object dump complete.

あ! パスと行番号!
そう、ここで出力するために渡してるんです
そっか、これを見ればどこでメモリリークしたかがわかるんだ!
 __FILE__ と __LINE__ は普通にプログラムの中で使えるから、便利そう
ならどんどん使ってもいいかも
あれ?  malloc() を使った時って……
そのときには自動的にこのふたつを渡してくれるから
ってことは、普通に使っててもこの情報は出るんだ
そういうこと。いちいち __FILE__ と __LINE__ を渡してたら大変だから
ね。で、 _malloc_dbg() にはデバッグ用に様々な機能が入ってます
今のメモリリークがわかるのもそうだよね
そう。見方は Version 11.09 ( No.209 ) を参照ってことで。でも、その
他にもデバッグ用の機能があるんです。 _malloc_dbg() で取ってきたアド
レスを直接見てみて
ほい。ブレークポイントで止めて、アドレス見て、メモリウィンドウで表
示っと
メモリウィンドウを見ると、こういうふうになっていると思います

                                                        FD FD FD FD
CD CD CD CD CD CD CD CD CD CD CD FD FD FD FD 
↑返ってきたアドレスが指してる場所。

ん? どういうこと?
えっと、まず _malloc_dbg() で確保したメモリ領域は

CD CD CD CD CD CD CD CD CD CD CD 

って感じに 0xCD が各要素に入れられます
 0xCD ?
そう。こうすることで、そのポインタが _malloc_dbg() で作られたのか
どうかとか、使う前に何か書き込まれてないか、とか調べる事ができま

使われる前?
プログラムが複雑になると、どっかよくわかんないところを経由してポイ
ンタを返したりするから、そういう時に
途中で変えられたりしてないか調べる時に使うわけね
そういうこと。で次に前後の FD について。 _malloc_dbg() は、実は指
定されたサイズのメモリは確保しないんです
え?
指定されたサイズよりも、前4バイト、後ろ4バイト、合計8バイト多め
にメモリを確保するんです
それが

                                                        FD FD FD FD
CD CD CD CD CD CD CD CD CD CD CD FD FD FD FD 

の FD が入ってる場所のこと?
そういうこと。この余分に作られた場所には 0xFD が入れられます。これ
は、配列のサイズを超えて書き込んだかどうかを調べるために使います
ってゆーと

    char ch[10];
    ch[10] = 'A';

みたいなこと?
そうそう。 Version 6.14 ( No.114 ) の【バッファオーバーフロー】を
検出するための機能なんです。実際にこれを試してみます

void Use_malloc_dbg_overflow()
{
    // このデータが入る領域を確保します。
    const char *const DATA = "あいうえお";

    // 小さく確保します。
    char *pch
        = (char *)_malloc_dbg
            ( strlen( DATA ) - 2    // ここ。
            , _NORMAL_BLOCK
            , __FILE__
            , __LINE__
            );

    // コピーしてから出力。
    strcpy( pch, DATA );
    TRACE( "%s\n", pch );

    // 解放します。
    _free_dbg( pch, _NORMAL_BLOCK );
}

 - 2 してあるから入りきらないわけね。じゃ、ビルドして実行。げげ

Debug Error!
Program ...(略)
DAMAGE: after Normal block (#86) at 0x00421690

ってダイアログが出た
 _free_dbg() は、メモリを解放するときに前4バイトと後ろ4バイトを
見て、それが 0xFD じゃない場合にはこういうエラーを出すんです
それでオーバーフローをチェックするわけね
あともうひとつ、 _free_dbg() は解放したら次のように 0xDD を入れま


                                                        DD DD DD DD
DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD 

これの意味は?
これは、解放した後に使ったときにそれがわかるように。たとえば

    // 解放します。
    _free_dbg( pch, _NORMAL_BLOCK );
    // もう解放したけど使っちゃったりとか。
    TRACE( "%s\n", pch );

って、本当はしちゃいけないんだけど _free_dbg() を呼び終わったポイ
ンタを使ったときとか
これをするとわかるの?
はっきりわかるわけじゃないけど、こうしておけば解放済みのポインタ
をもう一度使った時に
わかるものね。文字列消えてるんだから
というわけで、 _malloc_dbg() には色々なメリットがあるんです

/*
    Preview Next Story!
*/
何もしなくても勝手にこういうのできてるって便利ねー
次回は便利じゃない場合の話
げげ
 CString を使わないで文字列をくっつけたりとか
いつか、 _malloc_dbg() を自分で作ってみようとか言わないよね
……
あのー……
というわけで次回
< Version 11.15 文字列配列の拡張 >
につづく!
……僕作れないし
うっ
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。