トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
VisualStudio
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\n
[ トップページ ]
[ ____CommandPrompt ] [ ____JScript ] [ ____MySQL ] [ ____Cygwin ] [ ____Java ] [ ____Emacs ] [ ____Make ] [ ____Perl ] [ ____Python ] [ ____OpenGL ] [ ____C# ] [ ____StyleSheet ] [ ____C++ ] [ ____Winsock ] [ ____Thread ] [ ____VisualStudio ] [ ____C ] [ ____Win32API ] [ ____Lua ] [ ____PhotoShop ]
ヘッダ検索
___

■ CommandLine.からの実行




___

■ 下準備

___

■ IncludePath.LibraryPath.を通す

    Compiler と Linker のパスを通す

  基本の IncludePath, LibraryPath を通す
  VisualStudio では 環境変数 INCLUDE, LIB にあるパスを検索する
  そこで profile などで設定しておく

  # VisualStudio Install Directory
  VS=d:/vs
  INCLUDE=$VS/VC/include
  LIB=$VS/VC/lib

WARNING ENV:INCLUDE.LIBはVS2005では環境変数を設定しても正しく動作しない // /useenv すれば OK devenv.exe /useenv
___

■ Directory.構成

    $VS
      /VC   // C++ 用 Directory
        /lib
        /include
        /bin
            /cl.exe
            /link.exe
            /lib.exe
      /VB
      /VC#
WARNING 2005, 2008 が混在した環境で, lib, exe の設定を間違えると以下のエラーがでる 必ず build 設定を合わせること header の違いによるものと思われる 解決策として lib, exe 共に, 同一バージョンでビルドして Link すれば治る。 thiscall std::_Container_base::~_Container_base(void)" (__imp_??1_Container_base @std@@QAE@XZ) が関数 "public: __thiscall std::_Vector_val< class IndexBuffer *,cl ass std::allocator< class IndexBuffer *> >::~_Vector_val< class IndexBuffer *,clas s std::allocator< class IndexBuffer *> >(void)" (??1?$_Vector_val@PAVIndexBuffer@ @V?$allocator@PAVIndexBuffer@@@std@@@std@@QAE@XZ) で参照されました。
___

■ チュートリアル(Tutorial)


___

■ とりあえずビルドして実行ファイルをつくる

簡単なコードを用意
    #include< stdio.h> 

    int main() {
      printf( "test\n" );
      return 0;
    }
main.cpp をコンパイルしてリンクする
    cl  main.cpp
    出力実行ファイル名を指定する。
    cl /out:test.exe   main.cpp
POINT すべてのコンパイルオプションをファイル出力しておくと便利。
    cl /help > d:/cl_doc.txt
___

■ Compile

ファイル単位でコンパイルして、リンクをする

    //  /c でコンパイルのみの指定
    cl /c main.cpp

    // /out:FILE  で出力実行ファイル名の指定をする
    link  /out:test.exe  main.obj
___

■ Debug.のためのビルド設定

次の設定が必要になる。
      デバッグ情報(シンボルテーブル)の生成  /Zi, ZI
      最適化オフ                            /Od
      Debug 用の RunTime を指定する          /MDd

      デバッグ情報の生成                    /DEBUG
    // デバック用のオプションを指定してコンパイル
    cl /MDd  /Zi  /Od  main.cpp

    // そしてリンク
    link  /DEBUG main.obj
WARNING pdb ファイル名( Path )を勝手に変更しないこと exe に pdb のパスが書かれているデバッガがシンボル情報を見つけられなくなる "main.exe のデバッグ情報が見つからないか一致しません"
    // 名前をかえてみる
    mv main.pdb  foo.pdb
POINT 正しくシンボルテーブルが読まれているかは [ 出力 ]ウィンドウで確認できる。 'test.exe': 'D:\test\release\test.exe' を読み込みました。シンボルが読み込まれました。 // ここは /MD にしているから // /MTd にしても Windows System DLL の Symbol は Load されない 'test.exe': 'C:\WINDOWS\system32\ntdll.dll' を読み込みました。シンボルが読み込まれていません。 'test.exe': 'C:\WINDOWS\system32\kernel32.dll' を読み込みました。シンボルが読み込まれていません。 'test.exe': 'C:\WINDOWS\system32\msvcrt.dll' を読み込みました。シンボルが読み込まれていません。 プラグインを開発する時は, 実行ファイル本体のシンボルテーブルは存在しない。 その場合はデバッグ開始時に次のような表記がでる。
    app.exe のデバッグ情報がみつからないか, または一致しません。
さらにデバッガは exe が参照する DLL を順番にロードする。 ここでデバッグ対象の DLL のシンボルが読み込まれているか確認する。
    app.exe': 'd:/dll/test.dll' を読み込みました。シンボルが読み込まれました。
___

■ /Zi /ZI /Z7

DESC 生成する Debug.情報 の種類を指定する POINT Debug.情報とは 変数や関数の名前, 型, 行番号のリストのこと サードパーティのライブラリを配布する場合は .pdb ファイルを持たない利点あり ただし プリコンパイル済みヘッダーの .obj ファイルは リンク フェーズおよびデバッグで必要です .pch オブジェクト ファイルに型情報だけがある (コードはない) 場合は /Yl (デバッグ ライブラリの PCH 参照の挿入) も指定してコンパイルする必要あり POINT 次の指定だけでも Debug.情報を生成できる
    cl /Zi main.cpp
POINT VisualStudio 上の設定は次のようにする
    Compile Option
      全般 > Debug.情報の形式 
               > 無効                 // BP に Hit しない
               > ProgramDatabase(/Zi) // BP に Hit
              > エディット コンティニュ用プログラム データベース 
    Linker
      Debug > Debug.情報を生成
              > いいえ             // pdb ファイルが生成されない && BP に Hit しない
              > はい ( /DEBUG )    // pdb ファイルが生成         && BP に Hit 
            


___

■ SymbolTableを作成する


    // Debug をするには SymbolTableを作成する
    // そのための option として /Zi を指定

    cl /c /Zi main.cpp 

    // vc90.pdb ( Program Data Base File が作成される )


    // obj ファイルに組み込むには /Z7 を指定する
    // main.obj のサイズが大きくなることがわかる
    cl /c /Z7 main.cpp
WARNING Debugger が外部の SymbolTable を見つけるためには同一箇所に置く必要がある

    pdb file は Debuger が SymbolTable を見つけるため以下の要件がいる

       exe と同名
       同一 Directory に配置


    d:/src/main.exe
    d:/src/main.pdb

___

■ DLL.を作成する

    int add( int a, int b ) {
      return a + b;
    }
    // コンパイル
    cl /c dll.cpp

    // リンカーに DLL を作成するように指示する
    link  /DLL  /EXPORT:add  dll.obj    
___

■ DLL.の.Debug

POINT DLL の Debug を開始できる Project は 次の 2 つ DLL をコールする実行可能ファイルプロジェクト DLL を作成するプロジェクト POINT DLL を作成したプロジェクトからデバッグを開始するには DLL のデバッグに使用する実行可能ファイルを指定する
    構成 > Debug > Command 
            d:/myapp/myapp.exe
___

■ Debug.に役立つ関数

___

■ DebugBreak(__debugbreak)

SYNTAX void DebugBreak(); DESC 現在のプロセスでブレークポイント例外を発生させる デバッガに信号を送り何らかの処理を強制的に実行できる プロセスがデバッグ中でないときは 標準例外ハンドラの検索ロジックが使われます ほとんどの場合 未処理のブレークポイント命令のために呼び出し側プロセスは終了する
___

■ __debugbreak

SYNTAX __debugbreak(); DESC コンパイラの組み込み関数 DebugBreak __debugbreak を呼び出した場合の動作は その位置にブレークポイントを設定することと同じ。
___

■ debug.有無の開始

DESC c-f5 : debug なし 開始 f5 : debug あり -> 違い break point の判定 POINT c-f5 で実行した場合, terminal に実行結果が停止して表示される WARNING assert がスキップされるわけではない( assert は _DEBUG にたしいて有効 )
___

■ debug.開始directoryの設定

DESC SE > RMB > 構成プロパティ > debug > 作業 dir POINT SE > RMB > スタートアップ プロジェクトに設定 --------------- // ( 以下従来の方法 ) -> SE > Debug > 新しいインスタンスを開始 ( これで修正可能な場合もある ) path の問題かどうかは, shell から直接実行することで確認できる.
___

■ 条件付きbreakpoint

DESC 条件: 条件式が真の場合に停止 -> 2. 値が変更:
      i  :
      *p : p の指す値
       
      3. hitcount :
    for loop の際に使用      
      i >= 2
      i*i >= 10
      strcmp( data[i], "aaa" ) == 0 ERR
      pow( i, 2 ) >= 10 ERR 
___

■ 混合モード

DESC ソースコードとコンパイラによって生成されたアセンブリコードを 交互に混ぜて表示するモード。 POINT クラッシュしたアドレスがわかっている場合にデバッグで役にたつ。
    Debug > Window > 逆アセンブル ( Alt - 8 ) 
現在のコードに移動する。
    右クリック > 次のステートメントの表示
ステップ実行( F10 )をした場合は, アセンブラコードの単位で一行ずつ実行される。

      // ソースコードと
      7: main()         

      // アセンブリコードが交互に表示される
      0040B7B0   push        ebp
POINT アプリケーションがクラッシュした場合に表示されるダイアログを見れば, どこで落ちたかわかる。 障害モジュールの名前: test.exe
___

■ スタティックライブラリをつくる(StaticLibrary)

DESC スタティックライブラリとは、コンパイル済みのオブジェクト( *.obj )をアーカイブしたもの。 LINK はしないので, Linker の設定は不要 よく利用するモジュールは StaticLibrary として用意しておくと 実行ファイルをつくるときに、コンパイルせずにリンクだけで完了するので便利。 math のモジュールをつくる場合
    math
      vector.cpp
      matrix.cpp
$(VC)/VC/bin/lib/Lib.exe を利用してアーカイブする。
    // コンパイルして
    cl /c vector.cpp  matrix.cpp

    // アーカイブする
    lib   vector.obj  matrix.obj
作成した StaticLibrary を利用する場合はコンパイル済みなので link するだけで完了する。
    link  main.obj  math.lib  kernel32.lib
WARNING Library 内の関数のみが lib に含まれる PlatformSDK などを利用するなら, exe 側で LINK すること POINT C/C++ > コード生成 > ランタイムライブラリ の修正を忘れないこと ( 大量のエラーがでる ) POINT Application 側で Debug するには pdb というファイルが必要 これを lib と同じ場所においてやる必要がある POINT Application 側は次のような設定をする C/C++ > コード生成 > ランタイムライブラリ DLL なし 版にきりかえる WARNING DLL, exe を作成するときは利用してはダメ POINT LibraryManager のこと
___

■ Debug.する


___

■ Debug関連の設定

デバッグするには問題箇所の内容を見るため、 ソースコードにブレークポイントをしかける。
    Break Point の設定   ソースコードの左側を設定
開始をするには、 F5 を押す。
    Debug > デバッグ開始
ブレークポイントの箇所でプログラムの実行が停止するので F10, F11 で一歩ずつプログラムの動作を調べる。
    F10  :  
    F11  :  
一時的に無効にすることもできる。
    Debug > 一時的に無効 | 有効にする
property : exe のカレントパスと引数を設定
___

■ マクロを使う


___

■ ビルドする環境を変更する

環境ごとに処理を変えたい場合は、マクロ変数の値におうじて処理をかえる。
    #if BUILD_TARGET == BUILD_TARGET_WIN32
    typedef __uint32 uint32_t

    #else
    #include< stdint.h> 
    #endif
cl /D"BUILD_TARGET" main.cpp
    #ifdef BUILD_TARGET
    typedef int uint32_t;
    #else
    # include< stdint.h>
    #endif
___

■ Comment.別エラー対処



___

■ cl.exe.の起動中に.Error.が発生しました

原因 何かの理由で VisualStudio の PATH がとおっていない VC/bin/cl.exe
___

■ オーバーロードされた関数functionのC.リンケージの2回以上の宣言は許されません

オーバーロードされた関数'function'のC.リンケージの2回以上の宣言は許されません DESC extern "C" void foo(); extern "C" void foo( int ); overload func を非修飾にすることはできないということ
___

■ PROJ0019

ProjectBuildError たとえば Build.前のイベントにエラーがある 呼び出し先のどこかでエラーを起こしている
___

■ LINK_ERROR

___

■ LNK2005

MESSAGE 既に MSVCRT.lib(MSVCR80.dll) で定義されています SYNTAX Symbol( 本名 )は Object で定義されています。 DESC リンク時に複数のモジュールで同名のシンボルがある時に発生する。 main.cpp に void func() がある
    void func(){
      printf( "main func()" );
    }
    int main() 
    {
      // func() をコールする。
      func();
      return 0;
    }
module.cpp にも同名の void func() がある。
    void func(){
      printf( "module func()" );
    }
リンカーがどちらの func() を利用すればいいか分らないのでエラーとなる。 名前が重複しないようにすれば解決する。
    cl   main.cpp   module.cpp
リンク時に以下の理由で発生するエラー。
    // 自作のModule
    -------------
    A.obj
      MSVCRT.lib  // Complile 時の指定で埋め込まれている ( 動的 LINK する予定 ) 
                   
    -------------

    // 他からひろってきた Module
    -------------
    module.obj
      MSVCRT.lib  // 別の Object は静的 LINK する予定
                   
    -------------
Linkerからすると、どちらのlibを利用すべきか分らないことになる。 解決方法 1. 自分のつくった Obj の CRT のリンク先を よその Module の CRT のリンク先にあわせる 2. 自分のつくった Obj の CRT のリンク先と同じものを指す Module を LINK する
___

■ LNK4098

DESC リンクする CRT ライブラリの指定がモジュールごとに異なっている。 例えばデバッグ版とリリース版が混ざっていると発生する。
    // リリース版を指定
    cl /c  /MD  main.cpp

    // こちらは デバッグ版を指定
    cl /c  /MDd module.cpp
    link  main.obj  module.obj
解決するには、すべてのコンパイル単位で CRT の指定をそろえる。
    cl /c  /MD  main.cpp
    cl /c  /MD  module.cpp

    cl /c  /MDd  main.cpp
    cl /c  /MDd  module.cpp

    cl /c  /MT  main.cpp
    cl /c  /MT  module.cpp
実際におきるケースは既にあるコンパイル済みの外部ライブラリをリンクするときに発生する。 POINT Compile した obj ( Library )を link するときに CRT の指定が統一されてないとおきる 外の Library だけではなく, わざと cpp 単位で設定をかえるとおきる
    LINK : warning LNK4098: defaultlib 'LIBCMT.lib' は他のライブラリの使用と競合しています
    /NODEFAULTLIB:library を使用してください
C, C++でよく使う printf() はコンパイルしてライブラリという形で用意されてる 必須のライブラリをランタイムライブラリという POINT
    Runtime Library とは必須の Library ( よく使う Library ) のこと
デバッグ用とかマルチスレッド用、MFCを使う場合、DLLを使う場合などでライブラリを変える必要がある どのライブラリとリンクするかは VisualStudioでプロジェクトがやってくれるので大抵は気にする必要はない 何か別のライブラリを使いたいという場合に面倒になる そのライブラリがリリース用の libcmt.lib とリンクするように指示が組み込まれていて でもデバッグしたいから自分はlibcmtd.libとリンクしたい場合に問題になる そのライブラリのlibcmtd.libとリンクするバージョンを用意すれば解決する そこで libcmt.lib とリンクさせないようにする VCで他の Lib( obj ) をリンクするメッセージが出る LINK : warning LNK4098: defaultlib "msvcrtd.lib" は他のライブラリの使用と競合しています; /NODEFAULTLIB:library を使用してください LINK : warning LNK4098: defaultlib "nafxcwd.lib" は他のライブラリの使用と競合しています; /NODEFAULTLIB:library を使用してください LINK : warning LNK4098: defaultlib "libcmtd.lib" は他のライブラリの使用と競合しています; /NODEFAULTLIB:library を使用してください よく、「スタティックライブラリでMFCを使用」と出ていたので、「共有DLLでMFCを使用」に変更していたが ランタイムライブラリが VisualStdio で シングルスレッド マルチスレッド(DLL) マルチスレッド で3種類。デバッグ、リリース版で計6種類用意 、 MSVCRT.lib マルチスレッド(DLL) Release /MD(コンパイルオプション) MSVCRTd.lib マルチスレッド(DLL) Debug /MDd LIBCMT.lib マルチスレッド Release /MT LIBCMTd.lib マルチスレッド Debug /MTd ------------------------------------------- VS2005 からはない LIBC.lib シングルスレッド Release /ML LIBCd.lib シングルスレッド Debug /MLd コンパイラーオプションでの設定は
  「プロジェクトの設定」 > 「C/C++」 > カテゴリ「コード生成」
POINT ライブラリで作成したときにリンクしたランタイムライブラリと 現在のアプリで使用している RunTimeLibrary で異なっているためにエラーが出ている ライブラリのソースコードがあれば コンパイルオプションをアプリと同じオプションに変え作成しなおせば直せる ソースコードがなければ、ライブラリのオプションにアプリを合わせないとだめ アプリが 「マルチスレッド」 ライブラリが「マルチスレッド(DLL)」の場合 警告は出るが、使える。 POINT Library 側ですべての 構成を用意すること
     \md\test.lib
     \mdd\test.lib
     \mt\test.lib
     \mtd\test.lib
使う側では
    test.lib

    LibraryPath で読込先を変更する

    // Release 版
    /mt

    // Debug 版
    /mtd
LINK : warning LNK4098: defaultlib ' MSVCRT ' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。 /data/tool/vc2005/VC/bin/mt.exe /nologo /manifest debug/win32beep.exe.manifest -outputresource:debug/win32beep.exe
___

■ Pragma.一覧


___

■ Linker.に.lib.を指定する

DESC
    // Linker に対する 指示( pragma )
    #pragma comment(lib, "winmm.lib")

    // src( .cpp )にしている
    #pragma comment(lib,"wsock32.lib")
___

■ GUI







___

■ 検索

___

■ Symbolの検索(c-s-F)

    編集 > 検索と置換 > folda を検索して置換.  ( Symbol を列挙可能 )
DESC 現在の project のみを調べる 調べたい project を SE から選択 c-f > 現在のプロジェクトにチェック VC CRT リファレンス F1 > 検索する文字列[ alloca ], フィルタ条件[ Visual C++ ドキュメント ]
___

■ Debugテクニック

___

■ BreakPoint

___

■ CallStackWindow

DESC 関数呼び出し stack(frame) が表示される debug > window > local POINT call stack == 現在 呼出し中の stack 呼び出し処理を返却 adr を格納するにも使用 thread には 1 callstack が存在 stackframe == sub rougin 毎に stack に格納する情報 frame の領域は stack ptr( register の一種 ) を使用して access する DESC break point までの最短 呼び出し 履歴 関数呼び出し履歴 debug > window > 呼び出し履歴 stack として表現 WARNING すべての関数の call 履歴ではない
    startup() -> winmain() -> App::run() 
    -> App::end() -> App::quit()
POINT 呼び出し元のDLLもリストされる。 ソースがある場合にのみ、ブレークポイントを設定できる。
___

■ _malloc_dbg

// Memory を確保する部分を決める _malloc_dbg( NORMAL_BLOCK );
___

■ Process.に.Attach

WARNING Express Edition は未対応
___

■ その他


___

■ ビルド前のイベント

DESC property > ビルドイベント 各projビルド時に起動する.exe の設定 EX test.bat( sln 相対 )
___

■ .proj(file)をひとつのslnにimportする

DESC SE > RMB > 追加 > ( 既存 | 新規 )Project
___

■ Class.図

c-m-c -> Diagrasm
___

■ 環境設定(Customize)


___

■ MACRO.をつくる

Tool > Macro > MacroExplorer
___

■ ErrorCode


___

■ C1083

MESSAGE file `` が開けない DESC Link, Compile , PreCompileHeader などの file が見つからない SOL PATH を変更する
___

■ C2017

Define の \ の跡に SPACE があった 要は Escape は "" ないにないとだめ
___

■ C2589

class Foo{}; Foo::int a; ..\console.cpp(70) : error C2589: 'int' : スコープ解決演算子 (::) の右側にあるトークンは使えません DESC [ :: ] の右側には Class, Struct, Union 名のどれかを指定すること。 または 任意のメンバだけですよ ! クラス、構造体、または共用体の名前がスコープ解決演算子 (::) の左側にあるとき 右側のトークンにはクラス、構造体、あるいは共用体のメンバを指定する必要があります それ以外の場合、右側には任意のグローバル識別子を指定できる スコープ解決演算子はオーバーロードできない 次の例では C2589 エラーが生成されます
___

■ C2220

MESSAGE 警告はすべてエラーとして処理されますエラーが発生したため、オブジェクトまたは実行可能ファイルは生成されませんでした DESC コンパイルオプション "/WX" を指定したため Warning をエラー扱いにしてコンパイルが中断された。 Warning をエラー扱いにしたくないなら /WX を指定しない、または すべての Warning をなくす。
    // error C2220: 警告をエラーとして扱いました'object' ファイルは生成されません
    // warning C4101: 'i' : ローカル変数は 1 度も使われていません    

    int main() {
      int i;
      return 0;
    }
___

■ C2632

MESSAGE 'type1' の後に 'type2' を記述するのは正しくありません DESC int, float

    // Type Identifier が連続するといわれる
    int float i;   // C2632

    // bool が定義すみの環境では C2632
  <   typedef unsigned char bool;
___

■ C2653

..\foo.cpp(56) : error C2653: 'std' : 識別子がクラス名でも名前空間名でもありません [ std ] という Class, NameSpace は知りません と Compiler がいっている
___

■ C4100

参照されない 仮引数の警告 WarningLevel4 の対策 解決方法
    消す || 参照する. (void)arg; || arg;   // (void) 型に cast 
MESSAGE ';' : 制御が空の文が見つかりました意図した記述でしょうか DESC if (1); 制御文の後に ; があるときにでる EX int main() { int i = 0; if (i); // C4390 i++; } POINT MACRO を展開したときにこうなる可能性がある
___

■ C4390

MESSAGE ';' : 制御が空の文が見つかりました意図した記述でしょうか DESC if (1); 制御文の後に ; があるときにでる EX int main() { int i = 0; if (i); // C4390 i++; } POINT MACRO を展開したときにこうなる可能性がある
___

■ C4267

DESC 64bit 環境の size_t 型から, 小さいサイズの型に変換する際に発生する。 size_t は環境ごとに次のように定義されている
    // 32bit
    typedef unsigned int  size_t;

    // 64bit
    typedef __int64 size_t
___

■ C4244

MESSAGE '引数' : 'type1' から 'type2' への変換です。データが失われる可能性があります。 DESC 浮動小数点型が整数型に変換されました。データが失われた可能性があります。 互換性のある型を使用するようにプログラムを変更するか 別の論理をコードに追加するかして、変換される値の範囲が使用する型と常に互換性があるようにする
    int f(int x){ return 0; }
    int main() {
       double x = 10.1;
       int i = 10;
       return (f(x));   // C4244
       // try the following line instead
       // return (f(i));

       // C4244
       float f = 10;
    }
範囲内にあるときも同様になる
    float f = 1000;

  WARNING
    // 範囲外にあれば int 型のデータは float 型へ変換した際に欠落する
    float f = 1024 * 1024 + 1;
    float i = f;
引数' : 'unsigned int' から 'float' への変換です。データが失われる可能性があります。


___

■ C4018

MESSAGE 'expression' : signed と unsigned の数値を比較しようとしました。 C4018: '< ' : signed と unsigned の数値を比較しようとしました。 signed 型の数値と unsigned 型の数値を比較するには、コンパイラで signed 型の値を unsigned 型に変換する必要があります。 signed 型と unsigned 型をテストするときに どちらか一方の型をキャストすると解決することがあります。 POINT マイナスの値と比較するとエラーが発生する 逆に正の値しか扱わない場合はエラーにならない

    for( int i=0; i< listLog.size(); i++ ){


___

■ C4800

MESSAGE 'int' : ブール値を 'true' または 'false' に強制的に設定します (警告の処理) 'type' : ブール値を 'true' または 'false' に強制的に設定します (警告の処理)。 非 bool 値を bool 型に代入するか強制的に変換するとこの警告が生成されます。 値 true または false しか取らない int 変数を bool 変数に代入しており、 bool 型として再宣言できる場合が含まれます。 bool 型を使用するように式を書き直すことができない場合は、式に "!=0" を追加して bool 型にできます。 式をただ bool 型にキャストしても、この警告が生成されます (設計仕様)。
// compile with: /W3
   int i = 0;

   // try..
   // bool i = 0;

   bool j = i;   // C4800
   j++;

___

■ C4291

MESSAGE 'void *Test::operator new(size_t,unsigned int) throw()' : 初期化コードが例外をスローすると、'new' 演算子を使用しているとメモリを解放しません。 DESC 宣言' : 初期化コードが例外をスローすると、'new' 演算子を使用しているとメモリを解放しません。 仮引数付きの new が使用されていますが 該当する仮引数付きの delete がありません。 new 演算子でオブジェクトにメモリを割り当てると そのオブジェクトのコンストラクタが呼び出されます。 コンストラクタが例外をスローした場合は、オブジェクトに割り当てられていたメモリを解放する必要があります。 new 演算子と一致する operator delete 関数がない場合、メモリの解放はされない。 余分な引数を付けずに new 演算子を使用し、/GX、/EHs、または /EHa の各オプションでコンパイルして例外処理を有効にすると コンストラクタが例外をスローしたときに delete 演算子を呼び出すコードが生成されます。 仮引数付きの new 演算子 つまり割り当てサイズ以外の引数を伴う形式の new 演算子を使用すると、 コンストラクタが例外をスローしたときにも、 delete 演算子を呼び出すコードは生成されます。 これは、メモリを割り当てた仮引数付きの new 演算子と一致する仮引数付きの delete 演算子がある場合だけです。
      仮引数付きの new 演算子と一致する仮引数付きの delete 演算子が定義されていないため、警告 C4291 が生成されます。
      この問題を解決するには、main の前に次のコードを挿入します。
      オーバーロードされた operator delete 関数のパラメータは、最初のパラメータを除き、
      すべてオーバーロードされた new 演算子と一致することに注意してください。
    // throw を宣言すると 例外が投げられることになる
      void* operator new(size_t t, unsigned int id ) throw();

    // 宣言をしないと エラーにならない
      void* operator new(size_t t, unsigned int id ) ;

___

■ C4305

MESSAGE 'identifier' : truncation from 'type1' to 'type2' 識別子が小さい型に変換されるため、情報が失われます。

    // float 型に double 型の値をいれる発生する
    v.set( 0, 0.142857, 0.342857 );

    
// 型に合った値をいれればなおる
    v.set( 0.1f );

warning C4305: '引数' : 'double' から 'float' へ切り詰めます。
___

■ C4312

MESSAGE 'type1' からより大きいサイズの 'type2' へ変換します。 DESC この警告は 64 ビットの移植性の問題を検出します。 64 ビットの型に対して 32 ビットの値を割り当てようとしました。 32 ビット int または 32 ビット long を 64 ビットポインタにキャストしています。 符号の拡張が発生する場合、 一部の環境では これは安全でない変換になります。 int 型よりもサイズが大きいポインタ型に負数が割り当てられると 符号の拡張 が発生するため ポインタ型の値が int 型の値と異なるメモリ アドレスを参照するようになります。 この警告は /Wp64 が使用されている場合にのみ出される。
    // C4312.cpp
    // compile with: /W1 /Wp64 /LD
    void* f(int i) {
       return (void*)i;   // C4312
    }

    // OK
    void* f2(__int64 i) {
       return (void*)i;
    }
___

■ C4313

MESSAGE 'function' : 書式指定文字列内の 'format specifier' が 'type' 型の引数 %d と競合しています POINT printf() の format 指定子 が, 引数の型と矛盾したときにおきる。
    {
      void *p = malloc( 1024 );

      // ERROR
      //    64bit pointer 
      printf( "%d", p );             

      // OK
      printf( "%p", p );             
      printf( "%Id", p );
    }
64 ビット整数を保持できる %d 書式指定子に 32 ビット ポインタを渡している。 この警告が有効なのは /Wp64 オプションを使用している場合だけ
___

■ C4313

___

■ オーバーロードのどれも、すべての引数の型を変換できませんでした

DESC 問題箇所の関数がどれもオーバーロードする関数にならないということ。 引数が間違っているかチェックすること。
___

■ C4996

MESSAGE DESC セキュリティ的に推奨されない関数が利用されている。
    FILE *fp = fopen( "test.txt", "r" );
warning を消すには _CRT_SECURE_NO_WARNINGS を定義するか、 warning プラグマ を利用する
    #pragma warning(disable : 4996)    
    cl /W4 /D"_CRT_SECURE_NO_WARNINGS" main.cpp
___

■ C4530

MESSAGE FILE(LINE) : warning C4530: C++ 例外処理を使っていますが、アンワインドセマンティクスは有効にはなりません。 /EHsc を指定してください。 原因 標準 C++ ライブラリを使用するプログラムは、 C++ の例外処理を有効にしてコンパイルする必要がある。 ( 理由は ライブラリが例外処理をつかっているから ) 解決方法 /EHsc オプションを有効にする。
    [C/C++] > [コード生成] > [C++ の例外を有効にする] 

    cl /EHsc 
    // 標準ライブラリを利用する
    #include< string> 
    std::string s( "test" );
標準ライブラリを利用する場合は、例外処理を有効にしてコンパイル(コード生成)をする。
    cl /EHsc test.cpp
標準ライブラリを利用しないでも C++例外処理を使うと( try { 文の箇所で ) warning が発生する。
    try {
        throw "例外が発生しました";
    }
    catch( const char* str ){
      printf( "例外をキャッチしました\n" );
    }
デストラクタがすべてのオブジェクトに対して呼び出されない場合があります。 ただし初期化されていない関数ポインターを通じて関数呼び出しを実行しようとして その関数として呼び出す前に作成した パラメーターのオブジェクト たとえば構造化例外が発生する場合これらのオブジェクトに アンワインドするスタック中に呼び出されたデストラクターはありません。 REFERENCE Exception
___

■ リンカーオプション(LinkerOption)





___

■ Runtime

___

■ /implib

SYNTAX /IMPLIB:filename DESC Link で生成される ImportLibrary 名を filename に上書きする Default は basename test.dll ならば test.lib この Option の指定は必須ではない UI Linker > 詳細 > ImportLibrary POINT この Option は必須ではない
___

■ /LD

WARNING この Option 自体は lib.exe のものではない // cl の option のひとつ
    cl /help
DESC Link 時の指定 DLL を作成する これをつけると _main() がないと怒られない
    // dll を build する
    cl /LD /EHsc dll.cpp

    // 2 つの Source 
    cl /LD /EHsc dllA.cpp  dllB.cpp


    // DLL 名を指定する
    //    test.dll, test.lib  が作成される
    cl /LD /EHsc dllA.cpp  dllB.cpp  /link /out:test.dll /implib:test.lib

    // ImportLibrary を指定して Build
    cl /EHsc call.cpp test.lib

    // 実行
    ./call.exe

    // test.dll の名前を変更すると ERROR
    //    test.dll が見つからなかったため このアプリケーションは実行できませんでした
    mv test.dll test.dll_bk
    

    __declspec( dllimport ) void dllfuncD();

    int main()
    {
      dllfuncD();
      return 0;
    }

___

■ Debug

___

■ /DEBUG

DESC .exe ファイルまたは DLL のデバッグ情報を作成するために指定する デバッグ情報は、プログラム データベース (PDBファイル) に書きこまれる デバッグ用に生成された .exe や DLL には 対応する PDB ファイルの名前とパスが書かれている シンボルが読まれない時は以下のコマンドで調べること
    strings main.exe  | grep  "pdb"
デバッガーでプログラムをデバッグするときにこの名前が読まれ その PDB ファイルが使われる
    'vc.exe': 'D:\test\vc\debug\vc.exe' を読み込みました。シンボルが読み込まれました。
プログラム データベースの名前として ベース名 .pdb が使用され PDB ファイルのパスは .exe, .DLL ファイルに書かれる オーバーライドするには /PDB:filename で指定
    link   /DEBUG  /PDB:foo.pdb  main.obj
/Zd (行番号のみ) または /Z7 (C7 互換) を指定すると .obj ファイルにデバッグ情報が保存される /Zi (プログラム データベースを使用) コンパイラ オプションを指定すると .obj ファイルのデバッグ情報が PDB ファイルに保存されます リンカーはオプジェクトの PDB ファイルを探すときに まず .obj ファイルに書き込まれた絶対パスを検索し そこで見つからない場合は .obj ファイルの置かれているディレクトリを検索します オブジェクトの PDB ファイルの名前やディレクトリをリンカーに指定できない
___

■ /PDB

SYNTAX /PDB:filename DESC リンカーが作成するプログラムデータベース (PDB) の名前を指定する ( Default : プログラムベース名.pdb ) /DEBUG (デバッグ情報の生成) を指定すると デバッグ情報の入ったプログラム データベース (PDB) が作成される POINT pdb file の生成は /DEBUG で有効にする /DEBUG を指定しないと /PDB オプションは無視 PDB ファイルは 最大 2 GB Debug 中に Build すると pdb File を利用されていることがわかる 「リンカー入力としての .pdb ファイル」
___

■ DLL

___

■ /DLL

DESC DLL をビルドする この Option をつけて Compile すれば DLL が作成される( はず ) -> 2010.07.22 -> ちがった Link 時に指定する Option のため , Compile 時は特に関係ないはず DLL の作成方法
    POINT
      VC の version によっては wizard で DLL を選択できない
      でも Console Application を指定して 後で変更できる
      ( Option の設定しだいということ )
___

■ /export

DESC symbol を export する プログラムから関数をエクスポートして ほかのプログラムがその関数を呼び出せるようにする
  // こうするかわりに
  __declspec( DLL_EXPORT )  void func;

  // こうする
  // [追加のオプション] ボックスにオプションを入力
  /export:func
___

■ その他

___

■ MACHINE

DESC 対象となるアーキテクチャを指定する
      /MACHINE:x86
      /MACHINE:x64

      /MACHINE:I386
DLL は同一のタイプを利用しないと Module の対象 Computer と異なるといわれる
___

■ Entry

DESC EXE DLL 開始アドレス(名前)を指定する。 エントリポイントとはプログラムをメモリにロードした際に 実行をはじめる開始アドレスのこと。
    Linker > 詳細 > EntryPoint
    link  /Entry:main  main.obj
POINT 実はユーザーが書いたコードよりも前に、CRT( printf など ) の初期化、例外ハンドラの設定などが実行される。 これが _mainCRTStartup(), _WinMainCRTStartup() という関数で、C のランタイムライブラリ内にある。 次の流れになる。 main() は _mainCRTStartup() からコールされる。
    //      CRTの初期化をして         ユーザプログラムを開始
    OS ---> _mainCRTStartup()   --->  main()
WARNING エントリポイントはリンカーにまかせるべき。 そうしないと C ランタイムライブラリが正確に初期化され、 静的オブジェクト用の C++ のコンストラクタが実行されない。
    #include< stdio.h> 
    int main()
    {
      printf("test\n");
      return 0;
    }
CRT を利用しているが, main() を開始アドレスにする。
    cl /c main.cpp
    link /entry:main  main.obj
実行すると次のエラーがでる。
    runtime error R6030
    - CRT not initialized
デフォルトのエントリポイントは、アプリケーションのタイプ( SUBSYSTEM )によって決まる。
    SUBSYSTEM:CONSOLE  ならば  mainCRTStartup
    SUBSYSTEM:WINDOWS  ならば  WinMainCRTStartup
___

■ SUBSYSTEM

DESC オペレーティングシステムに .exe ファイルの実行方法を指定する。 サブシステムの選択によって リンカが選択するエントリポイント関数が決まる。 サブシステムの指定は どんな環境用のコードを出力するかを決定するために指定する。 POINT main() または WInMain() が定義されていると SUBSYSTEM オプションのデフォルト値が決まる。
    // main() がコード内で定義されていると、サブシステムとして暗黙に CONSOLE を選択することになる。
    int main() {
      return 0;
    }
明示する場合はリンカーオプションで指定する。
    link  /ENTRY:foo
WINDOWS アプリケーションにはコンソールは不要です。 このシステムにはユーザーとの対話用のウィンドウが作成されるからです。 WinMain() または wWinMain() が定義されていると、WINDOWS がデフォルト設定になる。 CONSOLE Win32 文字モードアプリケーションに対して使用する。 コンソール アプリケーションには、オペレーティングシステムからコンソールが与えられる。 main() または wmain() が定義されていると、CONSOLE がデフォルト設定になる。 POINT dumpbin /HEADERS でエントリポイントの開始アドレスがあることが確認できる。
    
undname.exe で C++ 修飾子前の名前を取得できる。
    undname ?Foo@@YGHPAUHINSTANCE__@@0PADH@Z   
___

■ Runtime

___

■ MANIFEST

WARNING crt.dll の場所を明示することが目的 mt.exe で埋め込まないと exe をビルド後の場所から移動すると実行できない ( たぶん manifest ファイルも配布すれば 埋め込むのも必須ではないと思う ) POINT VisualStudio では Default で manifest を実行ファイルに埋める GenerateManifest="true" Linker > Manifest > Manifest の生成
    // いらない
    link  /MANIFEST:NO  main.obj

    // つくる ( Default )
    link /MANIFEST main.obj

    // 指定しない場合でも作成される
    link main.obj
WARNING /MANIFEST:NO にしても 自動で exe には組み込まれない mt.exe を利用して埋め込む。 2 つの方法でアプリケーション || ライブラリに埋める インクリメンタル ビルドを実行しない場合は ビルド後のステップでマニフェストを直接埋める
    // Exe の場合
    mt.exe /manifest test.exe.manifest -outputresource:test.exe

    // DLL の場合
    mt.exe /manifest test.dll.manifest -outputresource:test.dll
インクリメンタル ビルドを実行する場合、上記のようにリソースを直接編集すると インクリメンタル ビルドが無効になり フル リビルドが実行されるため 異なるアプローチがいる バイナリをリンクして app.exe.manifest ファイルを生成 マニフェストをリソースファイルに変換 (インクリメント方式で) 再リンクして、マニフェスト リソースをバイナリに埋める
___

■ NODEFAULTLIB

LINK が参照を解決するときに検索するライブラリを引数 library で指定する コマンド ラインで指定したライブラリが検索される 2. /DEFAULTLIB オプションで指定したライブラリが検索される 3. obj ファイル内で指定した既定のライブラリが検索される /NODEFAULTLIB (すべての既定のライブラリを無視) オプションは、 /DEFAULTLIB:library の指定よりも優先されます /NODEFAULTLIB:library (無視するライブラリ) オプションと /DEFAULTLIB:library オプションで同じライブラリを指定すると、前者の指定が優先されるためそのライブラリは検索されません POINT 自分でコンパイルをする必要があるライブラリを使用する時は アプリケーションのランタイムライブラリの指定を、 ライブラリを生成した際の指定と同じにしておく必要がある。 異なる設定をしている時は、warning または、シンボルの二重定義でリンクできないなどの症状が出る。 Linker > Input > すべての既定ライブラリ無視 : YES RunTimeLibrary の指定が必要なとき MultiThread Application で SingleThread の指定が必要な場合 ライブラリとそれを利用するアプリケーションで、異なった設定を行った場合 /MD で作成されているライブラリを、/MT のアプリケーションで 利用しようとすると LIBCMT.lib での二重定義でエラーとなる
  error LNK2005: _printf は既に LIBCMT.lib(printf.obj) で定義されています
/MT で作成されているライブラリを、/MD のアプリケーションで 利用しようとすると warning が出るが動作はする
  LINK : warning LNK4098: defaultlib 'LIBCMT' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。
debugで作成されているライブラリを releaseで使用した場合ライブラリの競合が報告される ( 逆も同じ )
  // DLL 版でも同じ
  test.lib ( /MTd )
  app.exe  ( /MT ) 

  test.lib ( /MT )
  app.exe  ( /MTd ) 
___

■ 静的リンク

POINT /MT, /MD とは C の Runtime == C標準関数 の Runtime の LINK をどうするのか って聞いている 静的リンクとは アプリケーションプログラムをリンクした時に 必要なライブラリをプログラムに含める方式 リンク時にオブジェクトファイルを汎用ライブラリと共につなぎ合わせ 実行可能形式のバイナリを作成する 利点 必要なAPIやライブラリのバージョン間の互換性を気にしなくてもよい 欠点 実行可能形式のプログラムサイズが大きくなる 共有ライブラリをバージョンアップしたときにプログラムを再リンクする必要がある
___

■ 動的リンク

プログラムを実行する時に初めて 共有ライブラリあるいはダイナミックリンクライブラリ(DLL)と結合される方式を動的リンクという 実行時にプログラムの結合を行う方式 プログラム作成は 一般に大規模なプログラムをモジュールに分割して コンパイル後に オブジェクトファイルを汎用ライブラリと共につなぎ合わせて実行可能形式のバイナリを作成する これを静的リンクという それとは異なり プログラムを実行する時に初めて他のモジュールやライブラリと結合される方式を動的リンクと呼ぶ この動的リンクを使ったライブラリを 共有ライブラリあるいはダイナミックリンクライブラリ(DLL)という POINT DLL は ライブラリのひとつ 利点 実行可能形式のプログラムサイズを小さくできること 共有ライブラリをバージョンアップしたときにプログラムを再コンパイルする必要がない 欠点 ( DLL 地獄 ) 暗黙的に特定のバージョンの共有ライブラリの内部処理や仕様に依存していたプログラムが ライブラリのバージョンアップによって動作しなくなること バージョンアップした共有ライブラリに不良が作り込まれているとコンピュータ全体に影響が及ぶこと バージョンアップによる影響範囲を事前に特定できないこと 複数のバージョンのライブラリがシステム内に存在するときの動作が特定できないこと等がある
___

■ コンパイラオプション(CompilerOption)





    一覧を見るには cl.exe のヘルプを実行する。
    cl /help > cl_ref.txt
___

■ Code.生成

POINT リンカー渡されるすべてのモジュールは 同じランタイムライブラリ コンパイルオプション (/MD、/MT、/LD) を指定してコンパイルされている必要がある。
___

■ MT

マルチスレッド対応のスタティック バージョンのランタイム ライブラリが使用される。 POINT コンパイラにライブラリ名 LIBCMT.lib を .obj ファイルに挿入させるため、 リンカーは LIBCMT.lib を使って外部シンボルを解決できる。
    cl  /MT  main.cpp
テキストエディタでコンパイル済みのオブジェクトを見ると、以下の記述があることがわかる。
    /DEFAULTLIB:"LIBCMT"
___

■ MD

アプリケーションで マルチスレッド対応バージョンおよび DLL 対応バージョンのランタイムライブラリが使用されます。 _MT および _DLL を定義し、 コンパイラにライブラリ名 MSVCRT.lib を .obj ファイルに挿入させます。 このオプションを使用してコンパイルされたアプリケーションは、 MSVCRT.lib に静的にリンクされます。 このライブラリは、リンカーが外部参照を解決できるようにするコードレイヤーを提供しています。 実際のコードは MSVCR100.DLL, に入っているので、 MSVCRT.lib とリンクされるアプリケーションの実行時には、 MSVCR80.DLL にアクセスできるようにしておく。 Cランタイムライブラリを DLL として利用する場合は /MD オプションでコンパイルする。
    cl  /MD  main.cpp
WARNING /MD オプションでコンパイルしたオブジェクトをリンクすると manifest ファイルが生成される。 この manifest ファイルが DLL 本体の場所を示すため、実行ファイル(exe) と共に配布する必要がある。
    main.cpp
    main.obj
    main.exe
    main.exe.manifest
試しに manifest ファイルを削除してみる。
    rm  main.exe.manifest
もし実行ファイルのみの環境で実行するとエラーが出る。
    コンピュータに MSVCR90.dll がないため、プログラムを開始できません。
解決するには 実行ファイルと同じ場所に manifest ファイルを置く。 実際は manifest ファイルをいっしょに配布するのも手間なのでリソースとして実行ファイルに組み込む。
    d:/tmp/main.exe
    d:/tmp/main.exe.manifest
REFERENCE manifest
___

■ /Gm

DESC 簡易(最小)リビルド.変更部分のみを取得する
___

■ _DEBUG(NDEBUG)

DESC "Debug" 構成で Default ON になっている "Release" 構成では NDEBUG が有効。 POINT アサートをリリース時に無効にするには NDEBUG を有効にする。 $vc/include/assert.h には次のようにある
    #undef  assert

    // NDEBUG が ON ならば, assert は何もしない
    //    NDEBUG を OFF にすると assert にかかる
    #ifdef  NDEBUG

     #else

    #endif  /* NDEBUG */

___

■ 言語設定

___

■ /Ze

VC++ の拡張を禁止する 使用可能にするには /Ze 使用不能にするには /Za
___

■ PreProcessor

POINT PreProcessor への命令も含まれる /I< dir> インクルード検索パスに追加 /C コメントを削除しない /D< name>{=|#}< text> マクロを定義する /E stdout に前処理する /EP stdout に前処理する、#line なし POINT この手順なら /EP, /P は不要 SolutionExplorer RMB xxx.cpp > Property PreProcessor > 前処理済みファイルの生成 > 行番号つきか行番号なしを選択 // 生成 SolutionExplorer RMB xxx.cpp > Compile
___

■ /D

DESC マクロ変数を定義する。 コード内で環境によって処理を切り替えるときに使う。
    /D "WIN32" /D "TEST"

#ifdef WIN32
inclue < windows.h>
#else

#endif

    
___

■ #pragma(指令)

目的: コンパイラに特定の情報を渡すため指令(pragma) するため WARNING: pragma はC++ 標準、 しかし書式、内容はコンパイラ依存により移植性なし ANSI標準でない POINT: #pragma once 多重インクルード防止と同じ意味 主要なコンパイラ(VC、BC,gcc、CodeWarrior)では普通に #pragma onceが使用できる
___

■ Warning

/we< n> 警告 n をエラーとして扱う /wo< n> 警告 n を 1 度だけ表示する /w< l>< n> n の警告レベル 1-4 を設定する /W< n> 警告レベルを設定する (既定 n=1) /Wall 警告をすべて有効にする /WL 1 行診断を有効にする
___

■ WX

DESC 警告があった場合にエラー扱いにする。 これを指定するとすべての警告をなくさないと実行ファイルを生成することはできない。 POINT STL には /W4 警告もあるため 特定の warning だけを無視するには /wd を使う。 ソースコード内にも設定できる。
    // W3 に下げる
    #pragma warning ( push, 3 )
    #include< string> 

    // 戻す
    #pragma warning ( pop )

    // 無名の構造体です 警告を無効にする
    #pragma warning ( disable : 4201  )

    struct {
      int i;
    } p;

    // 元に戻す
    #pragma warning ( disable : 4201  )
___

■ /wd

DESC 指定した Warning を非表示( Disable )にする
    cl /wd:xxxx main.cpp
___

■ その他

___

■ /nologo

DESC Windows ... みたいな logo を消す。
___

■ /RTC

DESC RunTimeCheck ( 実行時のエラーチェックをする ) u : 未初期化変数のチェック s: スタックフレームのランタイム エラー チェックをする スタック ポインタの検証によって、スタック ポインタの破損を検出する。 呼び出し規約の不一致によって、スタック ポインタが破損することがある。 たとえば、 関数のポインタを __cdecl として宣言したが、 関数ポインタを使用して __stdcall としてエクスポートされた DLL の関数を呼び出した場合。
    
    23:   int cnt;
    24:   printf( "ret %d\n", cnt );

0031108E  cmp         byte ptr [ebp-39h],0 
00311092  jne         main+91h (3110A1h) 
00311094  push        offset  (311184h) 
00311099  call        _RTC_UninitUse (311A40h)   // チェック用の関数がコールされる。
0031109E  add         esp,4 
003110A1  mov         esi,esp 
003110A3  mov         edx,dword ptr [ebp-28h] 
003110A6  push        edx  
003110A7  push        offset ___xi_z+12Ch (315744h) 
003110AC  call        dword ptr [__imp__printf (3182C4h)] 

___

■ EHsc

___

■ 最適化(Optimize)

/O1 スペースを最小化する /O2 スペースを最大化する /Ob< n> インライン展開 (既定値 n=0) /Og グローバルな最適化を有効にする /Oi[-] 組み込み関数を有効にする /Os コード スペースを優先する /Ot コードのスピードを優先する /Ox 最大限の最適化 /Oy[-] フレーム ポインタの省略を有効にする
___

■ /Ox

DESC /Ox 最大限の最適化 /Os コード スペースを優先する
___

■ /Ot

DESC Code の Speed を優先
___

■ /Oi

DESC 組み込み関数を有効にする コンパイラへ 一部の関数呼び出しを組み込み関数に置き換えるように要求する コンパイラは 関数を呼び出した方が高いパフォーマンスが得られる場合は関数を呼び出すことがある
___

■ /Od

最適化をオフにする。 コンパイラはソースコードと同じようにアセンブラコードを生成する。 デバッグ時は余計な最適化をかけないように、/Od を指定する。 POINT 混合モードで見るとわかる。
    15:   int cnt = 0;
    16:   for( int i=0; i< 5; i++ ){
    17:     cnt ++;
    18:   }
    19: 
    20:   printf( "ret %d\n", cnt );

/O2 では cnt が push 5 としてコードが生成される。
    002C1C3B  push        5    
    002C1C3D  push        offset string "ret %d\n" (2C3950h) 
    002C1C42  call        dword ptr [__imp__printf (2C622Ch)] 
___

■ Debug用

___

■ C7

デバッグをするために利用するシンボルテーブルの形式を設定できる。 C7 MS-DOS 時代からのシンボルテーブルフォーマット 実行ファイルにシンボル情報が組み込まれるためファイルサイズは肥大化する。 WARNING ファイルサイズが大きくなることと, インクリメンタルリンクが無効になりリンク回数が増えるため利用しないほうがよい
    cl /Z7  test.cpp
PDB PDB フォーマットは一般的に利用されているシンボルテーブルのフォーマット。 実行ファイルとは別の2つのファイルに出力される。
      vc90.pdb : 型情報
      test.pdb : シンボル情報
POINT 実行ファイルに pdb を含むかどうかは実行ファイル内にある文字列を調べればわかる。 "D:/vc/test/test.pdb" といったパスが埋め込まれている。
    bash>  strings  test.exe |  grep "test.pdb"
___

■ /Z7

DESC obj file の中に Debug.情報 を組み込む( 古い形式 )
___

■ /Zi

DESC デバッグ情報を生成 ProgramDataBase(pdb)を作成する Debug.情報の形式 型情報は、.obj ではなく .pdb に配置される /Zi を指定すると /debug が暗黙に指定される ( 内部的に指定したことになる ) POINT Debug 情報の形式を指定する ( ON/OFF ではない ) Linker の設定もあわせて変更する Obj file の Debug 情報を pdb file という別ファイルに保存する POINT Debug 情報とは 型情報 のこと
    cl /Zi e.cpp

    ls
    
    // 生成されるもの
    e.ilk
    e.pdb
    vc80.pdb

    // まだ作成されない
    nm e.exe
___

■ マニフェスト(manifest)

  


    manifest とは
    辞書をひくと "明示する" とある。

    何かというと動的にリンクする Cランタイムの DLL のパスを明示的に指定すること。
    
    今までは PATH がとおったところから順に読んでいた。
    しかし何かをインストールするたびに 異なるバージョンの DLL が上書きされて問題をおこす。

    そこでバージョンも含めて完全なパスを指名してやれ。 という発想になった。


    明示するには
     "実行ファイル名.manifest" という名前で実行ファイルと同じフォルダに置く
     リソースとして実行ファイルに埋め込む
manifest ファイルを生成するには、DLL 版 Cランタイムを指定してコンパイルする。
    cl /MD main.cpp
    link main.obj

    main.exe.manifest が生成される
main.exe 内部にないため, manifest の名前(パス)を変えると実行時に dll を見つけることができなくなる main.exe と同じ名前で同じ Directory に置くこと なお exe 内には どの DLL を利用するかは記述されている
    コンピュータに MSVCR90.dll がないため、プログラムを開始できません。
    コンピュータに MSVCP90.dll がないため、プログラムを開始できません。
    // strings でチェックできる
    strings  foo.exe  | grep "dll"
VisualStudio は デフォルトでは ランタイムライブラリ をスタティックリンクしない そのためランタイムが導入されていない環境では実行時エラーとなる POINT 以下のエラーは 実行ファイル( その manifest ファイルが指している )Runtime が見つかりません。 という意味
    // 以下を意図的に変更すると再現できる
    < dependentAssembly>
      < assemblyIdentity type='win32' name='Microsoft.VC90.CRT' 
          version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
XP このアプリケーションの構成が正しくないため アプリケーションを開始できませんでした アプリケーションを再度インストールすることにより問題が解決する場合があります Vista このアプリケーションのサイド バイ サイド構成が正しくないため アプリケーションを開始できませんでした 詳細については アプリケーションのイベント ログを参照してください このエラーを解決するためには クライアントにランタイムを配布する必要がある
    Visual C++ 2005 再頒布可能パッケージ (x86) 
ご丁寧に次のようにかいてある
  Microsoft Visual C++ 2005 SP1 再頒布可能パッケージ (x86) は
  Visual C++ で開発されたアプリケーションを
  Visual C++ 2005 がインストールされていないコンピュータ上で実行するために必要な
  Visual C++ ライブラリのランタイム コンポーネントをインストールします
POINT ファイルサイズは増えるスタティックリンクしておいたほうが混乱は少ない POINT 最大の問題
    「共有ライブラリに対し互換性を失うような変更が行われた場合にライブラリを呼び出すプログラム側がそれを区別することができない」
    特にOS本体に同梱されるライブラリにおいてこのような変更が行われるとその影響範囲は広範囲になる
ソフトウェアのインストーラがシステムの共有ライブラリのバージョンチェックを行わず古いバージョンに置換してしまうことでも発生する DLL 地獄とは ダイナミックリンクライブラリ (DLL)や Component Object Model (COM)コンポーネントなどのバージョンアップによって 以前のバージョンのDLL・COMコンポーネント等に依存して動作するアプリケーションが動作しなくなる現象のこと 最近ではシステム保護機能や「サイドバイサイド(Side-by-Side, SxS)」と呼ばれる仕組みにより減ってきているが 全面解決には至っていない また Linuxにおいて対象ディストリビューションが異なるパッケージを使用したり サードパーティのパッケージ管理システムやレポジトリを使用することによりライブラリの依存関係が壊れ 同様の事象が発生することが多い
___

■ manifest.ファイルを組み込む

EXeと同じフォルダに、manifestファイルを置くだけ 例えば test.exe があるとすれば、test.exe.manifest を置く UTF-8形式のテキストファイルでなければならない、という点に注意 .manifestファイルの内容は次のとおり 外観を変えるだけならこれだけで良い resource に manifest を組み込む
   < ?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   < assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
       < dependency>
           < dependentAssembly>
               < assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" 
               processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*">
               < /assemblyIdentity>
           < /dependentAssembly>
       < /dependency>
   < /assembly>
あらかじめ用意した .manifest ファイルをリソースに埋め込む 上記で用意したファイルを test.manifestとするなら 例えば次のようにリソースファイルに追加する 追加する場所は 手動で編集するということで .rc2 ファイル内が良い // Editor RT_MANIFEST "res\test.manifest" 0. DLL の version(日付け) が異なるだけで動作しなくなった 特定のプロジェクトのマニフェスト ファイルの生成するには
   [リンカ] > [マニフェスト ファイル]  > [マニフェストの生成] 
新しいプロジェクトは デフォルトでマニフェストファイルを生成する ただし プロジェクトのマニフェストの生成プロパティを使用して プロジェクトのマニフェストの生成を無効にできます このプロパティを [はい] に設定すると このプロジェクトのマニフェストが生成されます それ以外の場合 リンカは アプリケーション コードの依存関係を解決するときにアセンブリ情報を無視し マニフェストを生成しません Visual Studio のビルド システムでは マニフェストを最終的なバイナリ アプリケーション ファイルに埋め込むか 外部ファイルとして生成できる [プロジェクトのプロパティ] > [埋め込みマニフェスト] > [マニフェスト ツール] > [入力と出力] マニフェストは 埋め込まれない場合は外部ファイルとして生成 最終的なバイナリと同じディレクトリに保存される マニフェストが埋め込まれる場合 ソース コードがオブジェクト ファイルにコンパイルされた後 リンカが依存アセンブリ情報を収集する 最終的なバイナリをリンクするときに 後で最終的なマニフェストを生成する際に使用される中間マニフェストが生成される 中間マニフェストの作成とリンクが終了した後 マニフェスト ツールが実行され 最終的なマニフェストがマージされて外部ファイルとして保存される プロジェクト ビルド システムは 次に マニフェストツールによって生成されたマニフェストが バイナリに既に埋め込まれているマニフェストと異なる情報を含んでいるかどうかを検出する バイナリに埋め込まれているマニフェストがマニフェスト ツールによって生成されたマニフェストと異なるとき またはバイナリに埋め込みマニフェストがない場合 Visual Studio は もう一度リンカを呼び出し 外部マニフェスト ファイルをバイナリ内にリソースとして埋め込みます バイナリに埋め込まれているマニフェストが マニフェスト ツールで生成されたマニフェストと同じ場合 ビルドは次のビルド手順に進みます マニフェストは 最終的なバイナリ内にテキストリソースとして埋め込まれます 表示するには 最終的なバイナリを Visual Studio でファイルとして開く マニフェストが確実に正しいライブラリをポイントするようにするには C/C++ プログラムのマニフェスト生成についての理解 manifest は XML ドキュメント POINT exe に組み込むということ ( 本質は 文字列と同じ ) isolated application のマニフェスト アプリケーションが実行時にバインドする共有 side-by-side アセンブリの名前およびバージョンの管理に使用されます side-by-side assemblyのマニフェスト そのアセンブリの名前 バージョン リソース および他のアセンブリへの依存関係を指定します つくりかた アセンブリの作成者が 規則および名前付けの要件に従って手動でマニフェスト ファイルを作成できる また プログラムが CRT MFC ATL などの Visual C++ アセンブリのみに依存する場合は リンカによってマニフェストを自動的に生成できます Visual C++ ライブラリのヘッダーにはアセンブリ情報が含まれているため ライブラリがアプリケーション コードにインクルードされると このアセンブリ情報は リンカによって最終的なバイナリのマニフェストが形成される際に使用されます リンカは マニフェスト ファイルをバイナリに埋め込まない 常に外部ファイルとしてマニフェストを生成する マニフェストが外部ファイルであることは すべてのシナリオにとって適しているとは限りません たとえば プライベート アセンブリでは 埋め込みマニフェストを使用することが推奨されます
___

■ Deprecate


  SYNTAX
    __declspec(deprecated)

  DESC
    将来, 非サポートにな予定であることの宣言. ( Compile 時に警告がでる )

  POINT
    Namespace, Class 名が変更された時は次のようにすると移行の警告を表示可能. 
       typedef foo::Test DEPRECATED Test;
       
       App 側
       Test cam;   // CMP は Camera だと認識する
           -> ついでに DEPRECATED があるので警告をだす

    Function
      int DEPRECATED func();
    Class
      class DEPRECATED Test { ... };
___

■ インクルード(INCLUDE)探索.INCLUDE_PATH

SYNTAX #include < path> #include "path" DESC 指定されたファイルの内容が挿入する < > INCLUDE_PATH を"基点"として検索する "" File( Source ) を相対として検索 なければ < > と同じ検索 POINT Library を include する時は < > を利用する
    dir
      xxx.vcproj
      main.cpp
      main.h

      // main.cpp

      // ERROR ( INCLUDE_PATH の指定がない )
      #include< main.h> 
      // OK ( main.h は main.cpp と同じ位置にあるから )
      #include"main.h" 


      // INCLUDE_PATH に vcproj を追加
      /I $(ProjDir)
      // OK
      #include< main.h> 
      
      command line から指定するときは 
      INCLUDE_PATH は cl の実行 Directory の相対になる



      test/include/main.cpp
                  tmp/
                     foo.h

      cd test
      cl /I include/tmp include/main.cpp   # foo.h へのパスがとおる
      cd test
      cl /I tmp include/main.cpp          # test/tmp となり ERROR

      # test/include へ移動
      cd include
      cl /I tmp main.cpp          # test/include/tmp となり OK

___

■ プリコンパイルヘッダ(PreCompileHeader)




  DESC
    頻繁に include するヘッダをコンパイルしておき, Linker で LINK する
    build 毎にかかる時間を軽減するため, header を中間ファイルにしておく
    Compile の高速化に役立つ
    変更度が低いものをまとめておくと良い。
    大量の header を読み込む際に 効果的

      
  1. SE > Cpp tab > precompile header を使用
      
    POINT
  1. win32 program では標準では stdafx.h という PCI を使用するように設定されている
     -> cpp によっては stdafx.h を include するようになっているので注意


     System 標準の include file
     Project 固有 && 共通 


  C/C++ > プリコンパイル済みヘッダ
     作成するか 
     使用するか
     使用しない  (/Yu)
// 作成先

    #include "sub.h"     // #define PI 3.14
    #include "StdAfx.h"  // ここより↑は 読み飛ばされる

    
    // ERROR
    printf ( "%d", PI );  

    // 常に file の先頭におくこと
    #include "StdAfx.h"

    // file 固有の header を include
    #include "foo.h"
    #include "foo.h"

  WARNING 
    使用するときは, すべてのソースに Include しないとだめ
    Compiler が探すため



    // #include "StdAfx.h"
    #include foo.h 


WARNING 複数の Project があるときは どの PreCompileHeader が LINK されるか不明 Header そのものは include のルールに従う
___

■ マクロ(define.macro)





___

■ WIN32_LEAN_AND_MEAN

DESC コンパイラにヘッダーからあまり使われない関数を省くように指示する。 軽くなるしれない。
___

■ WIN32

DESC VisualStudio の Project に Default で定義されている /D WIN32 _WIN32 とは異なる
___

■ Microsoft 固有のマクロ

DESC Microsoft 固有というのは Microsoft の Compiler を使ったことのとき
___

■ _WIN64

DESC platform x64 で有効になるマクロ
    // ポインタ型のサイズを 64 32 bit 環境で切り替える
    #ifdef  _WIN64
    typedef unsigned __int64    uintptr_t;
    #else
    typedef _W64 unsigned int   uintptr_t;
    #endif
___

■ _WIN32

DESC Win32 用アプリケーションに対して定義されます 常に定義されます Commpiler の CommandLine からは見えない しかし次のようにチェックすると, 定義されている


    // foo.c
    #include< stdio.h>
    int main() 
    {
    #ifdef _WIN32
      printf( "Defined" );     // cl はこちら
    #else 
      printf( "Not Defined" );  // gcc( cygwin はこちら )
    #endif
      return 0;
    }

___

■ ANSI C標準

___

■ __FILE__.__LINE__

ファイル名, 行数に置換される
___

■ __TIME__.__DATE__

日付、時刻に置換される。
___

■ 定義済みマクロ

VisualStudio ( cl.exe )固有の定義すみマクロは以下のものがある。
___

■ _WIN32

Win32 用アプリケーションに対して常に定義される。 検証用のコード。 CRT も含めて一切ヘッダをインクルードしないようにする。
    #ifdef _WIN32
      #error( "_WIN32 defined" )
    #endif

    int main() {
      return 0;
    }
ビルドして実行してみる。
    cl test.cpp && .\test.exe
___

■ _MSC_VER

DESC コンパイラバージョンを定義する。 Visual C++ 6.0 以降に対して 1200 以上として常に定義される。 POINT また VisualStudio 固有のプラグマを利用する時の環境の判定にも使える。
    #ifdef _MSC_VER
    #  pragma warning( push )
    #  pragma warning( disable : 4530 )
    #  pragma warning( disable : 4786 )
    #endif
___

■ デバッグ用マクロ

___

■ _DEBUG

_ASSERTE などのデバッグ用のマクロ展開の切り替えに利用される。 windows.h などで定義されている デバッグ関数を利用するときは、このマクロを定義する必要がある。
___

■ NDEBUG

DESC assert.h 内で assert マクロの展開を制御するためにユーザーが自分で定義するマクロ。 VisualStudio では Release 構成でこのマクロが有効になっている。 アサートを処理を無効化する。
    cl /D"NDEBUG" test.cpp

    #include< assert.h> 
    assert( !"test" );
___

■ 文字コード指定

___

■ UNICODE

使用する文字の文字コードを unicode に変更する場合に定義するマクロ。 UNICODEを定義してコンパイルすると unicode 用の関数が利用される。 ( VisualStudio 2008 環境 ) cl /P /D"UNICODE" test.cpp
    MessageBoxW( 0, s, s, 0x00000000L );
cl /P test.cpp
    MessageBoxA( 0, s, s, 0x00000000L );
___

■ _WIN32_WINNT

XP 固有機能を使う
___

■ WIN32

DESC Defined for WIN32 applications. Always defined. Microsoft specific
    // gcc   -E   main.cpp
    #include< windows.h> 

    #ifdef _WIN32 
        DEFINE _WIN32         // こっちが残る
    #else 
        NOT DEFINE _WIN32
    #endif

___

■ __WINDLL

_WINDLL Windows protected-mode dynamic-link library is selected with /GD.
___

■ __MINGW__

DESC コンパイラ判別用のマクロ。 MinGW 環境で Build すると Define される コンパイラを識別するために使う
___

■ __WIN32

cl gcc __WIN32 ○ × WIN32 × ×
___

■ DLL

DESC
___

■ __DEBUG

DESC Debug Build の Default MACRO stdio.h にも 定義されている
___

■ _LIB

DESC StaticLibrary のプロジェクトに設定されるマクロ。 cl -o main.exe ./main.cpp testlib.lib /IMPLIB:test.lib

      
    // obj をつくる ( Compile のみする )
    cl /c mod.cpp

    // Archive する
    lib mod.obj
    lib mod.obj /out:mod.lib

    
    // 同一の Symbol があれば ERROR ( と思ったら WARNING )

    
    libA.obj : warning LNK4006: 
    "void __cdecl subA(void)" (?subA@@YAXXZ) は libB.obj で定義されています。
    2 つ目以降の定義は無視されます。

    libA.obj : warning LNK4221: パブリック シンボルが見つかりませんでした。アーカイブ メンバにアクセスできません。
    lib libA.obj  libB.obj

    // libA.cpp
    void subA() {}

    // libB.cpp
    void subA() {}


    namespace で修飾すれば OK
    namespace bar {
    namespace foo {
      void subA(){}
    }
    }


    // こういう名前で変換される
    $nm libB.obj 
    00000000 T ?subA@foo@bar@@YAXXZ

    //  obj, lib( obj のセット )は symbol がある
    // しかし exe ( 実行 file )は存在しない
    // これは Linker の立場からすると 名前引きをしているということ
    
    // 一度, 結合( 完成 )すれば , 名前を書いておく必要がない
    //  Symbol と Debug 情報は異なる
___

■ File.構成


  .sln
    solution
      複数の vcproj を内包する
      ひとつのsolution は複数のproject をもつことができる


  .vcproj


    SE > file > import sln|proj
POINT ProjectFile.proj.はXMLで記述されてので,自由に編集可能, また生成もできる
___

■ パス

$(BitSuffix) = .64 ProjectName : xxx.proj の名前 OutDir : 出力 Directory 依存 Project がある時は $(OutDir)\lib に出力される IntDir : 中間ディレクト( Internal Directory ) // /I では FullPath に展開される $(SolutionDir) xxx.sln $(ProjDir) xxx.vcproj /Fo PROJECTNAME /Fp /Fd
___

■ .slnに複数の.projを作成

DESC file > new > project POINT build skip .sln > RMB > 構成 manager > build off 2. lib の扱い .vcporj > RMB > proj 依存関係 ON で lib 自動追加
___

■ 依存関係をもったプロジェクトの構築

DESC 複数の project をもつ solution ファイルは依存関係をつくることができる。
    test.sln
      app.vcproj      // アプリケーション本体
      mod.dll         // ライブラリとなるモジュール ( dll )
solution には以下の手順で project を追加する。
    SolutionExplorer > RMB > 追加 > 新規プロジェクト
                                  > 既存のプロジェクト
作成した後に、依存関係を定義する。 app.vcproj は lib.dll に依存するように指定する。 これによって プロジェクトのビルドの順番の指定と, library( lib ) が自動で追加される
    SolutionExplorer > RMB > プロジェクトの依存関係
依存先のプロジェクトの出力ファイルは依存元の 出力フォルダに生成される
    Debug/
          app.exe
          mod.lib
          mod.dll
POINT xxx.lib は __declspec( dllexport ) 宣言がないと出力されない
___

■ Project 構成

構成 とは Compile するときの"環境設定"( CommandLine Option )のこと 基本は次の構成
  1 Application == 1 Solution ( .sln )  
  1 Program == 1 Project ( .vcproj )  

Application( Solution ) は複数の Program( vcproj )をもつ
  Solution
      xxx.vcproj
      yyy.vcproj
      zzz.vcproj
簡単な Program なら 1 Solution , 1 vcproj

    Solution
      vcproj

___

■ vsprops

Project 設定を共有する makefile でいうと makefile_commmon みたいなもの 表示 > PropertyManager
___

■ その他


___

■ コンパイル時のエラー

Compiler モジュールがロードされない部分は実態がなくても コンパイルエラーにはならない モジュール単位のコンパイルが通れば、link時は結合されないだけ

  // foo() はコールされない
   void foo(void)
   {
      bar();  /* 実態はないがコールされないので問題なし(prototype は必要) */
    }
___

■ 使用しないlib について

POINT 不要な Lib があっても問題なし WARNING: linker はlib のlistからすべてを開こうとしているので、LIBPATH は必ず追加する POINT 必要なlib をVC のデフォルトとして設定しておくのあり [OpenGL32.Lib, etc ...], 次のパスをvcに通しておく header, lib は全project共通で使用できる LibPath List D:\Program Files\Microsoft Platform SDK\Lib\ ( OpenGL32.Lib ) IncludePath List C:\Program Files\Microsoft Platform SDK\Include( windows.h, OpenGL ) C:\Program Files\Microsoft DirectX SDK (February 2006)\Include ( DirectX )
___

■ Error.htm.をすぐみる

c-LMB
___

■ (デバッグ)Debug


___

■ Code.定義.Window

常に 関数の 定義 が見れる
___

■ メモリウィンドウ

    Debug > Window > Memory
DESC メモリウィンドウは指定したアドレスのメモリの生の値を見ることができる。 アドレスに変数や配列のアドレスを指定すれば 値がどのようになっているか確認できる。 使うにはアドレスに変数名または変数に割り当てられたアドレスを入力する。
     // 左にアドレス     右にメモリの値が表示
     x0FAF9226           1.6250034e-034 -2.1937332e-008 -3.7880127e-028 -1.4140254e-027  
     0x0FAF923E          1.065e-038#DEN  9.184e-041#DEN  2.6154749e-037 -4.2036835e+037 
     0x0FAF9256          -4.2991616e+008  2.8877576e+032  1.6274864e+025  3.9494500e+030 
     0x0FAF926E          1.378e-039#DEN -1.3114509e-015  1.2948590e-037  3.3325518e+019 
     0x0FAF9286          6.384579
POINT アドレスの指定はコード内で変数をマウスで選択してからドラッグすることでも見れる。 bin editor 同様 POINT Intel CPU はリトルエンディアンなので, 複数バイトのデータの下位のバイトを メモリ内の先におく。 デバッガでメモリアドレスを見る時は逆順になっているので頭の中で変換する必要がある。
    0x1234 < -> 0x34 0x12
メモリは単なるビットの列のため、指定したアドレスの先が int 型ならば 右クリック > 4バイトの整数 といったように表示したい形式を指定する。 長い文字列を表示しようとすると255文字で切り捨てに対応できる 2. 入力可能( dump 部分を編集可能 ) 3. 変数の値は メモリアドレス の若い順番に格納される a = 10 < -> 0x 0a 00 00 00 WARNING memory address に入れたシンボル名は その[ 変数値 ]が[ アドレス ]としてメモリ内容が表示される.
      // 次のように考える
      int a = 10;
      memory adress [ a ]  < -> memory adress [ 10 ] -> 不正
      memory adress [ &a ] < -> memory adress [ 0x0012E69C ] -> [0x 0a 00 00 00 ... ]

      // this;
      // thisはあるheap上のObjectのアドレスを指すので, 
      memory address [ this ] < -> [0x xx xx xx xx ... ] < - object の内容が表示 
___

■ ウォッチウィンドウ

ウォッチウィンドウでは次のことができる。 変数の参照と変更 関数の呼び出し 擬似レジスタの指定もできる。
    // Intel CPU レジスタで戻値を記録する
    @eax
変数の値に対して任意の式を記述できる
    // 1000 で割る
    @clk/1000

    // d ( 10 進表記をする )
    @clk,d
    
    // x ( 16 進表記をする )
    @clk,x
___

■ レジスタウィンドウ

EAX : 整数の戻り値を格納する ESP : スタックポインタ EIP : インストラクションポインタ ( 次の実行アドレスが設定されている )
___

■ モジュールウィンドウ(Module)

プログラム内でロードされているバイナリモジュールをリストする。
___

■ 呼び出し規約

___

■ グローバル変数へのアクセス

POINT グローバル変数は固定アドレスをもつアドレス参照にすぎない。
___

■ クイックウォッチの使い方

DESC var, adr 値を参照 POINT DCLK > SFT + F9 : ( watch 式追加 ) 2. *, & 演算子を使用して 値を見ることが可能 3. VAR=val 変更可能, ex. i = 10; 4. 配列参照, int arr[100]; 5. 任意の式を評価. ex. data == 0 -> true | false 5. cast式評価. ex. (unsigned)i; WARNING VAR adr 変更不可 2. 現在 scope VAR しか評価されない -> symbol xxx が見つかりません POINT watch pain は active なものだけが評価 watch pain に代入文を複数配置
___

■ 関数.変数参照

DESC F12 : 定義 jump c-F12 : 宣言 jump c-s-f12 : シンボル検索
___

■ ファイルから検索のタグジャンプ

DESC c-f : cur 位置の word 検索
___

■ インラインアセンブラ(Assembler)



___

■ コンパイルオプションで出力する

main.cpp から main.asm が出力される。
    cl /FA  main.cpp
___

■ インラインアセンブラの基本

SYNTAX __asm {} src には固定値, メモリ, レジスタが指定できる。 dst にはレジスタ, メモリ参照を指定する。 Intel CPU は src, dst 共にレジスタ参照はできない。 POINT メモリ参照をするには [] 内でアドレスを指定する。
    // *iptr と同じ
    [00400000h]
アドレスの前には取り出すサイズを指定する。 指定がなければ DWORD PTR が適用される。
    
POINT アセンブラの機能ではないが、インラインアセンブラを使う場合は C/C++ で宣言した変数が使える
    // n 
    dword ptr [n]

___

■ 定数を代入する

    mov         eax,20     ; eax = 20
    mov         ebx,0ffh   ; ebx = 0xff

___

■ メモリデータの扱い

        // ; eax = *address
        mov         eax,[address] 
        mov         [address],eax ; *address = eax
___

■ mov

SYNTAX mov dst, src DESC データを移動する
    // ecx, ebx を交換する
    mov eax,  ecx
    mov ebx,  ecx
    mov ecx,  ebx
変数に i に 10 をセットする
    int i;
    __asm  mov i, 10
___

■ push.pop

SYNTAX push src SYNTAX pop dst DESC スタックにワード, ダブルワードの値をプッシュする。 現在のスタックトップの値をもつ ESP レジスタの値を更新する。

    // 固定値, レジスタ, メモリアドレスなどを push できる。
    push 10

    // push すると ESP レジスタの値が 4 減る
    push 20

スタックは LIFO なので push と pop は逆順になる。
    push ecx
    push edx

    pop  edx
    pop  ecx
スワップにも利用できる
    push ecx
    push edx

    pop  ecx
    pop  edx
{{{ { __asm NOP } }}} {{{ move eax ecx }}}
___

■ cmp

SYNTAX cmp src, dst DESC 2つのオペランドを比較する。 減算した結果を EFLAGS レジスタの対応するフラグを設定する。
___

■ movs

SYNTAX movs dst, src DESC ESI レジスタに設定されているアドレスから EDI レジスタに設定されているアドレスへ データを移動する。 memcpy をする。
    mov ESI, src
    mov EDI, dst
    mov ecx, nr
    
    REP movs BYTE PTR [EDI], BYTE PTR [ESI]
___

■ プロローグ設定

    push EBP

    mov EBP, ESP
    
    // ローカル変数用に 20 byte 確保
    sub ESP, 20h
___

■ エピローグ設定

    // スタック値の回復
    mov ESP, EBP

    // 
    pop EBP
POINT __cdecl 規約では関数をコールした後にスタックを元の位置に戻すのはコールした側
    push  1h
    call  func
    add   esp,  4
___

■ call

SYNTAX call src DESC 関数をコールする。 コールした後は呼び出し元に戻る必要があるため、 戻るアドレスをスタックにプッシュする。 そのため呼ばれた側で ESP の値を見れば、戻るアドレスが分る。
    // ローカル関数の呼び出しは、目的の関数のアドレスを指定するだけ

    int func() {

    }

    __asm {
      call func
    }
___

■ jmp

DESC 絶対アドレスに実行を移す。
    // test というラベルに移動する。
    jmp test

    test:

cmp を使った場合は, JE, JG, JL などを結果に応じて移動できる。 C で if に相当する処理。

    // i と 0 を比較する
    cmp i 0

    JLE  less
    
___

■ LEA

SYNTAX lea DST SRC DESC src オペランドのアドレスを dst レジスタにセットする。
    // int 型の変数 i のアドレスを設定する
    
    int i = 0;
    LEA  eax,  i

    // char 型の配列のアドレスを設定する
    char buf[256];

    LEA ecx,  buf
    push ecx
    call  DWORD PTR [GetWindowsDirectory]

      int i = 7;
      00401016  mov         dword ptr [i],7 

      int &j = i;    
      0040101D  lea         eax,[i] 

      // i のアドレスを j の指す先に 移動する
      00401020  mov         dword ptr[j], eax       

___

■ inc.dec

    int i =  0;
    __asm {
      inc i
      dec i
    }
___

■ fld

SYNTAX fld DESC float 型データの push
___

■ fstp

SYNTAX fstp DESC float 型データの pop
    float i,j;
    i=10.0001;
    _asm{
        // i の値を push
        fld i 

        // j にポップする
        fstp j
   }    
___

■ fild

SYNTAX
___

■ fadd

SYNTAX fadd fD, fA, fB DESC float の加算 fAとfBの和をfDに格納する。(倍精度)
___

■ デバッグ用のビルド


___

■ プリプロセッサの出力をファイルにはく

マクロの展開に問題が起きているときや, チェックをしたいときに利用する。
    int main()
    {
      return __LINE__;
    }    
拡張子 .i というファイル( test.i )に展開結果が出力される。
    cl /P  test.cpp
    int main()
    {
      return 11;
    }
___

■ 標準インクルードパスを無視する

/X INCLUDE などの環境変数を無視して /I で指定したインクルードパスのみを対象にする。 異なるコンパイラが混在した場合に使うと便利。
    cl /X test.cpp
ビルドエラーになるので, CRT ヘッダのパスを明示的に指定する。
    cl /X  /I "d:/vc/VC/include/"  test.cpp
___

■ 構造体のアラインメント

/Zp 構造体メンバのアラインメントを指定する。
    // pragma でも指定できる。
    #pragma pack
___

■ マップファイルの生成

/MAP マップファイルを作成する。 シンボル情報をテキストとして保存する。
    link /MAP test.obj

    link /MAP /MAPINFO:LINES test.obj
___

■ NODEFAULTLIB

#pragma comment( lib ) で指定されらライブラリのリンクを無視する。 POINT CRT のヘッダには use_ansi.h のように以下の行があり, リンク時にライブラリを指定しなくても自動でリンクされる。 これを無効にするのが NODEFAULTLIB
    #pragma comment(lib,"libcpmt")
___

■ /VERBOSE

リンカがシンボルを検索する工程を出力する。 リンカが間違ったシンボルをリンクしているかチェックをしている時に便利。
    link /VERBOSE  test.obj
上の設定では大量のログが出力されるため ファイルだけに絞る。
    link /VERBOSE:LIB  test.obj
___

■ 生成される File の種類


___

■ suo(SolutionUserOption)

DESC .sln の設定ファイル
___

■ ncb

DESC Project DataBase
___

■ Thread

  DESC
    Step 実行中は , Thread ごとに Step 処理をしていることになる
    複数の Thread で混ざることはない


___

■ 64bit.用の.CompileOption.の設定をする


  


    以下の設定をすると 64 bit 環境になる

    /MACHINE (ターゲット プラットフォームの指定) が /MACHINE:IA64 または /MACHINE:X64 に設定されます

    [出力の登録] が無効になります詳細については、「 [リンカ] プロパティ ページ」を参照してください

    [ターゲット環境] が /env x64 または /env ia64 に設定されます詳細については
    「 [全般] ([MIDL] プロパティ ページ)」を参照してください

    [パラメータの確認] が消去され、既定値にリセットされる
                      詳細については、「 [詳細] ([MIDL] プロパティ ページ)」を参照してください
    
    [デバッグ情報の形式] は、
      Win32 プロジェクト構成で /ZI に設定されている場合

      64 ビット プロジェクト構成では /Zi に設定されます
      詳細については、「 /Z7、/Zi、/ZI (デバッグ情報の形式)」を参照


    /D (プリプロセッサの定義) 
        WIN32 -> WIN64 



___

■ 64.bit環境の作成

USAGE VC の install において 64 bit 環境を Install する 構成マネージャ > ActiveSolution > 新規 > x64 を選ぶ
___

■ Expressでの追加インストール

  wget http://download.microsoft.com/download/F/1/0/F10113F5-B750-4969-A255-274341AC6BCE/GRMSDKX_EN_DVD.iso
    wget http://download.microsoft.com/download/2/E/9/2E911956-F90F-4BFB-8231-E292A7B6F287/GRMSDKX_EN_DVD.iso
以下のようにかいてある。つまりコンパイラも提供してくれる。 The Windows SDK provides tools, compilers, headers, libraries, code samples, Help http://d.hatena.ne.jp/torutk/20100927/p1 http://msdn.microsoft.com/ja-jp/library/9yb4317s.aspx // iso のインストール http://oshiete.goo.ne.jp/qa/5534393.html cl コンパイラの場所
    /mydata/tool/vc/VC/bin/cl.exe


    64bit コンパイラ
    /mydata/tool/vc/VC/bin/x86_amd64/cl.exe

    
GUI から構成を選択できるようにする。
    wget  http://files.cppblog.com/xcpp/VCE64BIT_WIN7SDK.zip
___

■ バイナリが64bitか判断する方法

VisualStudio 付属のコマンド dumpbin を使うと確認できる。 FILE HEADER VALUES の最初の項目(machine)がx86かx64かで区別する。
    dumpbin /HEADERS  main.exe

    FILE HEADER VALUES
             14C machine (x86)
               3 number of sections
    FILE HEADER VALUES
                8664 machine (x64)
___

■ WOW64

WOW64 とは 64bit 環境で 32bit アプリケーションを実行するためのエミュレータのこと。 WARNING 64 bit アプリケーションではポインタの扱いに注意が必要。 32 ビット アプリケーションでは、IsWow64Process() を呼び出すことによって 実行されているのが WOW64 環境なのかわかる。
    BOOL b;
    IsWow64Process( GetCurrentProcess(), &b );
    
___

■ Keybind


  DESC

      Tool > Option > 環境 > Keyboard 
    keyboard map scheme 選択 > 名前をつけて保存
    command list を選択
    ショートカットキー box に アサインしたい key を打つ

  s-    : Shift   + 
  c-    : Control + 
  m-    : Alt     +

BIND c-l : cp line c-s-l : kill line c-c : cp line c-i : IncrementSearch ( c-f : Insensitive | Sensitive ) m-Drag : Rect Sel s-m-Drag c-k, c-c : Comment Sel c-k, c-u : unComment Sel c-r | c-w: Space 表示 c-\ | c-t: task 一覧表示 //TODO コメント c-m-b : BreakPoint 一覧表示. f12 : throw Exception W: インクリメンタル検索 F: VisualC++ document Edit.Find : c-f : 検索 Edit.FindinFiles: c-s-f : file 内検索 Edit.FindNext : f3 : 次の検索箇所 Edit.FindPrev : s-f3 : 前の検索箇所 Edit.Replace : c-h : 置換 Edit.ReplaceInFile : c-s-h : ファイル内置換 Edit.isearch : c-i : インクリメンタルサーチ Edit.r-isearch : c-i : 逆インクリメンタルサーチ 定義へ移動 : f12 戻る : c-f6 参照へ移動 : s-f12 宣言へ移動 : c-f12 -> (c-b : c-b に変更) symbol 検索: m-f12 tab 移動 : c-tab breakpoint : f9
___

■ WindowsLibrary


  DESC
    普段 無意識で LINK されているので, ちょいとメモ

    Project Default の値として 継承される
    kernel32.lib

___

■ kernel32.lib

D:/Program Files/Microsoft Platform SDK/Lib/Kernel32.Lib cd D:/Program Files/Microsoft Platform SDK/Lib/ nm kernel32.lib | grep " T .*@"
KERNEL32.dll:
00000000 I .idata$4
00000000 I .idata$5
00000000 I .idata$6
00000000 T .text
00000000 T _CreateDirectoryExA@12
         U __IMPORT_DESCRIPTOR_KERNEL32
00000000 I __imp__CreateDirectoryExA@12  
___

■ DLL2




___

■ Export.Import

DLL 内の関数を他のプログラムから使用できるようにすること 使う側: // DLL から LINK するため LINK ERROR しないように指示をする。 __declspec( dllimport ) 逆に Client 側から利用してもらうには, __declspec(dllexport) を宣言して Symbol 情報を出力する この設定をしないと .lib が出力されない 存在理由 LINKER に DLL 内に関数があることを知らせるため 名前を互いに明示的に表示することで アクセスできるようにする. EXport とは dll をテキストエディタやバイナリエディタで開くと 中に関数名が文字列として書かれてる これが「見える」ということで、検索可能であるということ。 static lib でも 関数名が見える。見えないと LINK できない。 DLL 版の .lib size は小さい しかも .lib には 文字列などの情報がない 複数の DLL を同一関数名で 暗黙LINK すると 先に lib に指定した方で Symbol を解決する 明示版でも同じはず
___

■ 使い方

declspec(dllexport)キーワードを使用する ( MS固有の予約語、ANSIC にはない )
       __declspec(dllexport) func();
       __declspec(dllimport) func();
2. def file を利用する POINT 関数名ではなく序数で公開するので、DLLのサイズが小さくなる
    以下の項目をファイルに記述
     1. ライブラリ名
      2. エクスポートする関数名

      LIBRARY DllTest
  DESCRIPTION "DLL-TEST"
  EXPORTS
        calcTest @1
        stringTest @2
___

■ dll のリンク方法

暗黙(静的)リンク : GetProcAddress() の代わりに lib を LINK する -> WARNING: 複数の DLL で同一の Symbol を利用する場合は不要. 関数の宣言 __declspec(dllimport) type func(type); // VC 固有なので注意 2. linker .lib を link .lib に関数名と序数が記述 3. DLL のロード 実行の準備前にロード 4. 関数とのbind .lib に記述した関数がないと実行時エラー 5. 暗黙 pro がコードに記述しなくても, load されるので暗黙的 6. 静的 linker がリンクした時点で, どの関数を使用するかが 決定するので静的
___

■ 明示(動的)リンク

関数の宣言、DLL の関数の宣言はしない ( 関数ptr のtypedef はあると便利 ) 2. linker linker のリンクは不要 ( 実行時に動的にコール ) 3. DLL のロード LoadLibrary() でロード 4. 関数とのbind GetProcAddress で関数名( 序数 )を指定することで関数ポインタを取得 5. 明示 pro がLoadLibrary() するので 明示的 6. 動的 LoadLibray, GetProcAddress で自由にコールできるので動的
___

■ DLL

DESC プログラムの実体をもつfile 関数名 | 序数 でエントリを保持 POINT 暗黙 .lib のエントリ情報を元に関数を bind 明示 GetProcAddress() で明示的に指定する。 POINT # dll 内の関数名、序数が表示する VC Cmd > dumpbin /exports foo.dll # dll 内の依存関係をしらべる # この DLL(Exe) を使うのに必要な DLL を表示 # たとえば LINK する xxx.lib を変更すると内容もかわる VC Cmd > dumpbin.exe /dependents foo.dll
___

■ DumpBin

DESC 実行ファイルから Symbol を出力するツール。 外部 の library でどのような関数があるか, 調べる際に利用する. VS の 関数名で BreakPoint をしかけると併用すると便利. // すべてを見るには dumpbin /all foo.exe // printf() でも MSVCR80D.dll に依存する export している関数を調べる。
    dumpbin  /export  test.exe
次のように出力される。
  Section contains the following exports for test.exe

    00000000 characteristics
    4F366DB1 time date stamp Sat Feb 11 22:31:29 2012
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001040 ?testexport@@YAHXZ
___

■ 使い分け

暗黙 プログラムが楽( headerを細工するだけで良い ) 明示 DLL の有無を問わない 特定の dir の DLL をロードする DLL file 名を定義ファイルに記述して、ロードできる。
___

■ .lib

DESC DLL 本体への入り口( アドレス )が記述されたファイル 入り口 == ( 関数名 | 序数 ) DLL load 時に .lib 内の関数をすべて ロードする
___

■ 序数

DESC dll の関数をあらわす一意の数字のこと POINT EXport する関数の数がかわると、DLL がもつ 序数が変化する 新たな .lib をリンクする必要がある
___

■ def

DESC dll に保持される、関数名、序数を定義するファイル SYNTAX ; 関数名と序数を指定
  EXPORTS
      testfunc @1
      foofunc  @2
POINT def file を使用する際は dllexport する必要はない 逆に dllexport することが、def file ですることを自動化している。 DLL, .lib に export 情報を組み込むこと意味
___

■ その他

___

■ header に関数名があるから lib は link 場合でも必要

DLL 本体への入り口 ( 関数名 , 序数 ) があるので 必須 関数宣言だけで DLL 内のどこを見ればよいか分らない。
___

■ dll lib file 名を変えることはできない。

A. lib ならば変更できる。 -> lib には [ この dll の この関数 ] という情報がある [ この dll ]は lib に記述すみ
___

■ __declspec(dllexport)

DESC DLL とは次の三つで構成される export : DLL として公開する symbol list 2. code, data : 公開する関数、変数の本体 3. import library : DLL の symbol を link するための OS への最低限の情報 以上のことを export は text editor で list を手書きでつくるが 自動でやってくれるのが__declspec(dllexport)
___

■ デバッグCRTライブラリ(DebugLibrary)


    VisualC++ にはデバッグライブラリがあるため
    メモリリークなどを検出できる。

    メモリリークを検出するには次のマクロを定義することで、実装する処理を切り替える
    #define __CRTDBG_MAP_ALLOC
    #include< crtdbg.h> 


    int main() {

    // 利用したいデバッグ機能をフラグで指定する。
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

     void *p = malloc( 256 );

    
    // プログラムの終了時にリークをチェックする。
     _CrtDumpMemoryLeaks();
      return 0;
    }    
ビルド設定は次のようにする。 デバッグ版のCRTを利用するため, コンパイル時のオプションで /MTd を選択する必要がある。
    cl /c -D_DEBUG /MTd -Od -Zi -W3 test.cpp &&   link -verbose:lib /debug test.obj
      
    // BAD
    cl /c -D_DEBUG /MT -Od -Zi -W3 test.cpp &&   link -verbose:lib /debug test.obj
WARNING _CrtDumpMemoryLeaks のログは OutputDebugString() として出力されるため コンソールへの stdout, stderr には出力されない。
___

■ _CrtSetDbgFlag

SYNTAX int _CrtSetDbgFlag( int newFlag ); DESC デバッグ用のヒープマネージャのオプションを指定する。 _CRTDBG_ALLOC_MEM_DF デバッグヒープ割り当てを有効にする。 _CRTDBG_LEAK_CHECK_DF プログラムの終了時に _CrtDumpMemoryLeaks を呼び出して、メモリ リークのチェックを自動的に実行する。
___

■ _CrtSetReportMode

SYNTAX int _CrtSetReportMode( int reportType, タイプ ( _CRT_WARN _CRT_ERROR _CRT_ASSERT ) int reportMode 出力先 ); DESC _CrtDbgReport、_ASSERT マクロ、_ASSERTE マクロ、_ASSERT マクロ、_ASSERTE マクロ、 _RPT、_RPTF、_RPTW、_RPTFW のマクロ、_RPT、_RPTF、_RPTW、_RPTFW のマクロ などの _CrtDbgReport、_CrtDbgReportW を呼び出すすべてのマクロが生成する特定のレポートの種類の出力先を指定する。 (デバッグ バージョンのみ) _CRTDBG_MODE_DEBUG メッセージをデバッガの出力ウィンドウ _CRTDBG_MODE_FILE ユーザー指定のファイル ハンドル _CrtSetReportFile を呼び出して、出力先となるファイルまたはストリームを定義します。 _CRTDBG_MODE_WNDW メッセージ ボックスを作成し メッセージと Abort、Retry、Ignore の各ボタンを表示する。 _CRTDBG_REPORT_MODE 指定された reportType の reportMode を返します。 アサートの出力を stderr とダイアログボックスに表示する。
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );  

    _ASSERTE( !"test" );
___

■ _CrtSetReportFile

SYNTAX _HFILE _CrtSetReportFile( int reportType, _HFILE reportFile ); DESC stderr にアサート結果を出力する。
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );  

     HANDLE h = CreateFile("c:\\log.txt", GENERIC_WRITE, 
        FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 
        FILE_ATTRIBUTE_NORMAL, NULL);

     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
     _CrtSetReportFile(_CRT_WARN, h);

     _RPT0(_CRT_WARN,"file message\n");

     CloseHandle(h);
___

■ _CrtSetDumpClient

SYNTAX _CRT_DUMP_CLIENT _CrtSetDumpClient( _CRT_DUMP_CLIENT dumpClient ); WARNING これは _CLIENT_BLOCK 型なので _NORMAL_BLOCK 型のリークにはフックできない。 DESC アプリケーションは、_CLIENT_BLOCK メモリ ブロックに格納されているオブジェクトをダンプする独自の関数を C ランタイムデバッグのメモリ ダンププロセスにフックできる この結果、_CrtMemDumpAllObjectsSince や _CrtDumpMemoryLeaks などのデバッグ ダンプ関数が _CLIENT_BLOCK メモリ ブロックをダンプするたびに、 アプリケーションのダンプ関数も呼び出される。 _CrtSetDumpClient を使用すると 簡単な方法でメモリ リークを検出し、_CLIENT_BLOCK ブロックに格納されているデータのコンテンツを検証またはレポートできます。 _DEBUG が未定義の場合、_CrtSetDumpClient の呼び出しはプリプロセスで削除される。 _CrtSetDumpClient は、dumpClient で指定されたアプリケーション定義の 新しいダンプ関数をインストールし、前回定義されていたダンプ関数を返す。 クライアント ブロックのダンプ関数の例は、次のとおりです。 void DumpClientFunction( void *userPortion, size_t blockSize ); userPortion メモリブロックのユーザー データ領域の先頭へのポインタです。 blockSize 割り当てられたメモリ ブロックのサイズをバイト単位で指定する。 クライアント ブロックのダンプ関数は、void を返す必要がある。 _CrtSetDumpClient に渡されるクライアント ダンプ関数へのポインタは _CRT_DUMP_CLIENT 型で、Crtdbg.h で次のように定義される。 typedef void (__cdecl *_CRT_DUMP_CLIENT)( void *, size_t );
___

■ _CrtDumpMemoryLeaks

SYNTAX int _CrtDumpMemoryLeaks(); DESC メモリ リークの発生時に、デバッグ ヒープ内のメモリ ブロックをすべてダンプする。 RET true : リークがある false : リークなし
___

■ _CrtSetBreakAlloc

SYNTAX long _CrtSetBreakAlloc( long lBreakAlloc // BP を設定する割り当て順序番号 ); DEP < crtdbg.h> DESC アプリケーションは、特定のメモリ割り当て位置にブレークポイントを設定し、 要求元までトレースすることによって、メモリ リークを検出できます 使用されるオブジェクト割り当て順序番号は、ヒープへの割り当て時にメモリブロックに割り当てられた シーケンシャル番号です _DEBUG が未定義の場合、_CrtSetBreakAlloc の呼び出しはプリプロセスで削除されます オブジェクト割り当て順序番号は Crtdbg.h で定義されている _CrtMemBlockHeader 構造体の lRequest フィールドに格納されます デバッグ ダンプ関数のいずれかが出力するメモリ ブロック情報のレポートでは 中かっこで囲まれて {36} のように表示されます
___

■ _CrtIsValidHeapPointer();

POINT Debug Library のみにあるため, /MTd にしないと LinkError つまり Option を切り替えることでリンクする Library を変更しているということ dll 内の heap を解放すると crash する 参照するだけなら 問題ない。
      char *p = testdll();
      _ASSERTE( _CrtIsValidHeapPointer(p) );

      // これで落ちる
      delete p;      
___

■ アサート(Assert)


    assert は ANSI C 標準マクロとして assert.h に定義されている。
    VisualStudio 環境では, Console アプリケーションは stderr に出力されて
    GUI アプリケーションでは メッセージボックスが出力される。

    POINT
      1つのアサートに対して1つのチェックをすること。
      assert( p != NULL );

      // これでは どちらのチェックに失敗したか不明。
      assert( p != NULL && cnt > 0 );
自前でマクロを再定義しておくと便利。 デバッグしやすいように、できるだけ情報( 式, メッセージ, ファイル、行 )を出力しておく。 do - while(0) をするのは if() assert() とあった場合の対策。
    void assertmessage( const char *exp, const char *msg, const char *file, int line )
    {
      printf("ASSERT FAIL: MESSAGE[%s] EXP[%s] FILE[%s] LINE[%d]", msg, exp, file, line );
    }

    #undef assert

    #define assert( cond, msg )                       \
    do {                                          \
          if ( !(cond) ) {                                    \
            assertmessage( #cond, msg, __FILE__, __LINE__ ); \
            DebugBreak();                             \
          }                                           \
        } while (0)
デバッグ以外のときはアサートは無効にする。
    #ifdef _DEBUG
    # define  assert( x ) do{ }while(0)
    #else
    # define  assert( x )
    #endif
___

■ _ASSERT(_ASSERTE)

assert は ANSI C 標準マクロであり, _ASSERT, _ASSERTE は VisualStudio 固有のアサートマクロ。 _ASSERTE は Expression(アサート式)を表示してくれるため、こちらの方がデバッグ時に役にたつ。
    #include< crtdbg.h> 

    _ASSERTE( !"test"  );

マクロの展開結果を見てみると、 ファイル名, 行, 式が _CrtDbgReport() に渡されていることがわかる。
    cl /D"_DEBUG" /P test.cpp


    (void) ((!!((!"test"))) || (1 != _CrtDbgReportW(2, L"test.cpp", 79, 0, L"!\"test\"")) || (__debugbreak(), 0));
___

■ クラッシュハンドラ


    アプリケーションエラーを表示する前に、アプリケーションのロジックを制御してしまう。
    

    


___

■ IsBadCodePtr

SYNTAX BOOL IsBadCodePtr( FARPROC lpfn // メモリのアドレス ); RET 0 : 有効 !0 : 不正なポインタ DESC 呼び出し側プロセスが 指定されたアドレスのメモリに対して読み取りアクセスができるか返す。 POINT NULL チェック以外にバッファオーバーランによって不正なアドレスを指すポインタも検知できる。
  {
    int *ptr = (int *)1;

//    int i;
//    ptr = &i;
    assert( IsBadCodePtr( (FARPROC)ptr ) == 0 );
  }

kernel32.lib
___

■ OutputDebugString

DESC 現在のアプリケーションのデバッガに文字列を送信する。
___

■ CRT


    インポート関数とは外部 DLL から公開されている関数のこと。
    
    C 標準ライブラリでも DLL からロードすることを選択できる。
    コンパイラは実際にジャンプする関数のアドレスではなく
    間接アドレスにジャンプするコードを生成する。



    /MD, /MT を変更すると混合モードでのアセンブラ表示で call 命令の引数が変わる。
    00401018  call        dword ptr [__imp__printf (406220h)]   

    00401018  call        printf (401029h) 
MessageBox などの WindowsAPI は /MT, /MD の設定によらず常に間接参照を使っての DLL内の関数呼び出しであることがわかる。
    00401034  call        dword ptr [__imp__MessageBoxA@16 (4253DCh)] 
dumpbin /imports を使うと Import Adress Table のアドレスがわかる。
    MSVCR90.dll
                4061FC Import Address Table
                4060B8 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                  10B _adjust_fdiv
                   CB __p__commode
                   CF __p__fmode
                  16A _encode_pointer
                   E0 __set_app_type
                   43 ?terminate@@YAXXZ
                   E3 __setusermatherr
                   96 __dllonexit
                  276 _lock
                  31C _onexit
                  160 _decode_pointer
                  173 _except_handler4_common
                  20B _invoke_watson
                  13F _controlfp_s
                  14B _crt_debugger_hook
                  13C _configthreadlocale
                  205 _initterm_e
                  204 _initterm
                   A0 __initenv
                  4CC exit
                   66 _XcptFilter
                  17C _exit
                  12C _cexit
                   9F __getmainargs
                  115 _amsg_exit
                  52E printf
___

■ VirtualQuery

SYNTAX DWORD VirtualQuery( LPCVOID lpAddress, // 領域のアドレス PMEMORY_BASIC_INFORMATION lpBuffer, // 情報バッファのアドレス DWORD dwLength // バッファサイズ ); 呼び出し側のプロセスの仮想アドレス空間にある範囲のページの情報を取得する。 指定されたアドレスから始まる連続ページのうち 次の属性で共通しているページに関する情報が取得できる。 ほかのプロセスのアドレス空間にある範囲のページに関する情報を取得するには VirtualQueryEx() を使う。
___

■ VirtualProtect

SYNTAX
___

■ VirtualProtect

SYNTAX BOOL VirtualProtect( LPVOID lpAddress, // コミット済みページ領域のアドレス DWORD dwSize, // 領域のサイズ DWORD flNewProtect, // 希望のアクセス保護 PDWORD lpflOldProtect // 従来のアクセス保護を取得する変数のアドレス ); 呼び出し側のプロセスの仮想アドレス空間内のコミット済みページ領域に対する アクセス保護をの状態を変更する。 コミット済みページに限ってアクセス保護値を設定できる。 指定された領域内のページがコミット済みではない場合、この関数は失敗し どのページのアクセス保護も変更しない。
___

■ MakePtr

___

■ Debugger


  
    コンソールプログラムならは Control-c で DBG_CONTROL_C 例外を発生させる。


  76FF15DE  add         esp,4

  
  混合ウィンドウでアドレスを見ると問題の箇所がわかる。

test.exe の 0x76ff15de でハンドルされていない例外が発生しました: 
0xC0000005: 場所 0x00000000 を読み込み中にアクセス違反が発生しました。  

    例外の種類には以下のものがある
     EXCEPTION_DEBUG_EVENT
          例外が発生した
            ブレークポイント例外
            

    
     CREATE_PROCESS_DEBUG_EVENT
          プロセスが実行前にロードされた時点で発生する。
          デバッガはこのタイミングで 逆アセンブルコードの表示など必要なことをする。


___

■ WaitForDebugEvent

SYNTAX BOOL WaitForDebugEvent( LPDEBUG_EVENT event, // デバッグイベントの情報が入った構造体へのポインタ DWORD time // 待つ時間 ( msec ) ); DESC デバッグ中のプロセスでデバッグイベントが発生するのを待つ。 WaitForDebugEvent 関数を呼び出すことができるのは デバッグ中のプロセスを作成したスレッドだけ。
___

■ ContinueDebugEvent

SYNTAX BOOL ContinueDebugEvent( DWORD dwProcessId, // 続行するプロセス DWORD dwThreadId, // 続行するスレッド DWORD dwContinueStatus // 続行状態 ); デバッグイベントを報告したスレッドをデバッガが続行できるようにします。 OS に継続を通知する。
___

■ CreateProcess

SYNTAX BOOL CreateProcess( LPCTSTR lpApplicationName, // 実行可能モジュールの名前 LPTSTR cmdline, // コマンドライン文字列 LPSECURITY_ATTRIBUTES lpProcessAttributes, // セキュリティ記述子 LPSECURITY_ATTRIBUTES lpThreadAttributes, // セキュリティ記述子 BOOL bInheritHandles, // ハンドルの継承オプション DWORD dwCreationFlags, // フラグ LPVOID lpEnvironment, // 新しい環境ブロック LPCTSTR sDir, // カレントディレクトリの名前 LPSTARTUPINFO pStartupInfo, // スタートアップ情報 LPPROCESS_INFORMATION pProcessInformation // プロセス情報 ); DESC DESC 新しい 1 個のプロセスと、そのプライマリスレッドを作成 Windows OS の元では 実行ファイルを開くことはプロセスの生成と同じ 任意のプログラムをコマンドラインで、あるいは引数付で実行することができます 実行開始時の状態を指定したり実行したプロセスやプロセスのメインスレッドのハンドルも得られるので プログラムの終了を待つなど柔軟な制御ができる 適当なエディタ機能とCreateProcess()を組み合わせれば 「編集したソースをコマンドラインでコンパイラに渡してコンパイル、コンパイル終了を待って実行」 という簡単な「統合開発環境」を開発することもできる lpProcessAttributes 構造体で子プロセスが 取得したハンドルを 継承 できるかどうかを指定する NULL を指定すると 取得したハンドルを継承できない ノートパッドを起動する。
    PROCESS_INFORMATION pi;
    STARTUPINFO si;

    ZeroMemory( &si, sizeof(si) );
    si.cb=sizeof( si );


    CreateProcess(
        NULL, 
        "notepad",
        NULL,NULL,
        FALSE,
        NORMAL_PRIORITY_CLASS,  // Thread Schedular の 優先順位 は普通
        NULL,NULL,
        &si,&pi 
        );

コマンドライン文字列は引数も含めてすべてを指定する。 コンソールウィンドウを新規に与えるには CREATE_NEW_CONSOLE フラグをたてる

    CreateProcess(
        NULL, 
        "ping localhost",
        NULL,NULL,
        FALSE,
        CREATE_NEW_CONSOLE,
        NULL,NULL,
        &si,&pi 
        );

プロセスの終了まちをする。
      WaitForSingleObject( pi.hProcess, INFINITE );
フラグは次のようなものを指定できる CREATE_NEW_CONSOLE 親のコンソールを継承せず新しいコンソールを持ちます。DETACHED_PROCESS フラグと同時に指定することはできません。 CREATE_NO_WINDOW コンソールアプリケーションを起動する場合にのみ有効です。 このフラグを指定すると、コンソールウィンドウなしでアプリケーションを実行する。 DEBUG_PROCESS 呼び出し側プロセスをデバッガ、新しいプロセスをデバッグ対象として扱う。 OS は、デバッグ対象のプロセス内で発生するすべてのデバッグイベントを呼び出し側スレッドへ通知します。 このフラグを指定してプロセスを作成すると 呼び出し側スレッド(CreateProcess 関数を呼び出したスレッド)だけが 関数を呼び出せます。 DEBUG_ONLY_THIS_PROCESS 呼び出し側プロセスがデバッグ対象であるときに、 このフラグを指定せずに CreateProcess 関数を呼び出すと 呼び出し側プロセスを扱っているデバッガは、新しいプロセスもデバッグ対象とします。 呼び出し側プロセスがデバッグ対象ではない場合、デバッグ関連の動作は発生しません。 プロセスの実行でブロックされるため、スレッドで CreateProcess を実行すると ユーザーの応答をうけることができる。

 DWORD WINAPI func(LPVOID lpArg) {

      PROCESS_INFORMATION pi;
      STARTUPINFO si;

      ZeroMemory(&si,sizeof(si));
      si.cb=sizeof(si);

      CreateProcess(NULL,(LPTSTR)lpArg,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
        NULL,NULL,&si,&pi);

      CloseHandle(pi.hThread);

      // 終了まち
      WaitForSingleObject( pi.hProcess, INFINITE );

      CloseHandle(pi.hProcess);

      PostMessage(hwMain,WM_USER,0,0);

      ExitThread(0);

      return 0;
  }
___

■ breakpoint

POINT ブレークポイントを仕込むには、インストラクションポインタの場所に ブレークポイント命令を入れるだけ。 Intel 系 CPU では ニーモニックは INT 3 。 オペコードは CC。
    __asm {
      INT 3
    }
POINT デバッガでブレークポイントを仕込むにはこのオペコードで上書きしてしまえばいい。
___

■ OpenProcess

SYNTAX HANDLE OpenProcess( DWORD dwDesiredAccess, // アクセスフラグ BOOL bInheritHandle, // ハンドルの継承オプション DWORD id // ハンドルを取得したいプロセスのID ); DESC 既存のプロセスオブジェクトのハンドルを開く。
___

■ GetCurrentThread

SYNTAX
___

■ GetThreadContext

SYNTAX BOOL GetThreadContext( HANDLE hThread, // 情報を取得したいスレッドのハンドル LPCONTEXT lpContext // コンテキスト情報 ); RET 0 : 失敗 !0 : 成功 DESC 指定したスレッドのコンテキスト( レジスタ( ISP, ESP )の値など )を取得する。 WARNING 実行中のスレッドには利用することができないので, SuspendThread() を使ってとめる。 情報を取得するには スレッドをとめる必要がある。 スレッドへの THREAD_GET_CONTEXT アクセス権が必要。
    CONTEXT    stCtx  ;
    stCtx.ContextFlags = CONTEXT_FULL ;

    GetThreadContext ( GetCurrentThread ( ) , &stCtx ) );

    // レジスタの値がとれる。
    stCtx.Eip;
    stCtx.Esp;
    stCtx.Ebp;

___

■ スタックトレース(StackTrace)

シンボルテーブル情報があればスタックトレースをできる。

#include< imagehlp.h>  
#pragma comment(lib, "imagehlp.lib")


LONG CALLBACK SWFilter(EXCEPTION_POINTERS *ExInfo)
{
  STACKFRAME sf;
  BOOL bResult;
  PIMAGEHLP_SYMBOL pSym;
  DWORD Disp;

  printf("例外発生\n");

  // シンボル情報格納用バッファの初期化 
  pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc(GMEM_FIXED, 10000);
  pSym->SizeOfStruct = 10000;
  pSym->MaxNameLength = 10000 - sizeof(IMAGEHLP_SYMBOL);

  // スタックフレームの初期化
  ZeroMemory(&sf, sizeof(sf));
  sf.AddrPC.Offset = ExInfo->ContextRecord->Eip;
  sf.AddrStack.Offset = ExInfo->ContextRecord->Esp;
  sf.AddrFrame.Offset = ExInfo->ContextRecord->Ebp;
  sf.AddrPC.Mode = AddrModeFlat;
  sf.AddrStack.Mode = AddrModeFlat;
  sf.AddrFrame.Mode = AddrModeFlat;

  // シンボルハンドラの初期化
  SymInitialize(GetCurrentProcess(), NULL, TRUE);

  // スタックフレームを順に表示する
  for(;;) {
    // 次のスタックフレームの取得
    bResult = StackWalk(
      IMAGE_FILE_MACHINE_I386,
      GetCurrentProcess(),
      GetCurrentThread(),
      &sf,
      NULL, 
      NULL,
      SymFunctionTableAccess,
      SymGetModuleBase,
      NULL);

    // 失敗ならば、ループを抜ける
    if(!bResult || sf.AddrFrame.Offset == 0) break;

    // プログラムカウンタから関数名を取得
    bResult = SymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, &Disp, pSym);
    
    // 取得結果を表示
    if(bResult) printf("--- 0x%08x %s() + 0x%x\n", sf.AddrPC.Offset, 
                       pSym->Name, 
                       Disp);
    else printf("%08x, ---", sf.AddrPC.Offset);
  }

  // 後処理
  SymCleanup( GetCurrentProcess() );
  GlobalFree( pSym );

  return(EXCEPTION_EXECUTE_HANDLER);
}



___

■ StackWalk

SYNTAX BOOL StackWalk( DWORD MachineType, // IMAGE_FILE_MACHINE_I386 ; HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, // 関数ポインタ PTRANSLATE_ADDRESS_ROUTINE TranslateAddress // NULL );
___

■ SymSetOptions

SYMOPT_LOAD_LINES : 行番号をロードする
    SymSetOptions ( dwOpts | SYMOPT_LOAD_LINES ) ;
___

■ SymInitialize

BOOL SymInitialize( HANDLE hProcess, PSTR UserSearchPath, // シンボル情報ファイルの検索パス BOOL fInvadeProcess ); RET TRUE : 成功 FALSE : 失敗 DESC プロセス用のシンボルハンドラを初期化する。 シンボルハンドラの観点では、 プロセスはシンボル情報を収集するときに利用できる便利なオブジェクトです。 シンボルハンドラを利用するのは、 デバッグ対象のプロセス用のシンボルをロードする必要のあるデバッガや他のツールです。
    HANDLE hProcess = GetCurrentProcess () ;

        if ( FALSE == g_cSym.SymInitialize ( hProcess ,
                                             NULL     ,
                                             FALSE     ) )
    

    if ( GetThreadContext ( GetCurrentThread ( ) , &stCtx ) )

___

■ GlobalAlloc

SYNTAX HGLOBAL GlobalAlloc( UINT flag, // 割り当て方法 DWORD sz // サイズ ); RET NULL : 失敗 DESC 指定された Byte 数を Heap から割り当てる。 POINT 「固定メモリ」と「移動可能メモリ」の二種類のメモリを割り当てる機能がある。 固定メモリ 割り当てたメモリ領域のアドレスが返される 移動可能メモリ メモリ領域を識別するハンドルが返され、メモリ領域自体は任意に移動される 移動可能メモリはvmem機構の存在しなかったWin16の時代の名残。 vmem機構の備わったWin32環境ではほとんど意味はない。 ただし、DDEやクリップボードなどへのデータの送受信など 特定の目的で使用する場合はある。

    // 固定 Memory Address として割り振る
    
    // Win32 では 物理 Memory の 移動, Swap はされる
    // 理論上は 固定 ということ
    // 
    GlobalAlloc( GMEM_FIXED, sz );

    
    // 仮想 Memory 空間を移動できる
    GlobalAlloc( GMEM_MOVEABLE, sz );

___

■ SymGetSymFromAddr

SYNTAX BOOL SymGetSymFromAddr( HANDLE hProcess, DWORD Address, // 検索したいシンボルのアドレス( シンボルの境界でなくてもかまいません。 アドレスがシンボルの先頭とシンボルの終わり ( シンボルの先頭にシンボルサイズを足した位置)の間にある場合そのシンボルが見つかる) PDWORD Displacement, // シンボルの先頭からの変位( オフセット)、または 0 を指定します。 PIMAGEHLP_SYMBOL Symbol // シンボル名を受け取る構造体 ); DESC プログラムカウンタから関数名を取得する。 指定されたアドレスに置かれているシンボルを検索します。
___

■ SymGetLineFromAddr

SYNTAX BOOL SymGetLineFromAddr( HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line ); DESC 指定されたアドレスに対応するソースコードの行、ファイル名を検索する。 SymGetLineFromAddr を呼び出すに Line バッファを割り当て、 構造体の必要なメンバ( サイズなど )をセットすること。
        IMAGEHLP_LINE stIHL ;
        ZeroMemory ( &stIHL , sizeof ( IMAGEHLP_LINE ) ) ;

        stIHL.SizeOfStruct = sizeof ( IMAGEHLP_LINE ) ;

        if ( 0 != SymGetLineFromAddr ( dwAddr  ,
                                              &dwDisp ,
                                              &stIHL   ) )
        {
            // Put this on the next line and indented a bit.
            pCurrPos += wsprintf ( pCurrPos                  ,
                                  _T ( "\n\t\t%s, Line %d" ) ,
                                  stIHL.FileName             ,
                                  stIHL.LineNumber            ) ;

            // オフセットがあれば                                  
            if ( 0 != dwDisp )
            {
                pCurrPos += wsprintf ( pCurrPos             ,
                                       _T ( " + %d bytes" ) ,
                                       dwDisp                ) ;
            }
        }

___

■ SymCleanup

SYNTAX BOOL SymCleanup( HANDLE hProcess ); DESC プロセスハンドルに関連付けられているすべてのリソースの割り当てを解除する。
___

■ ReadProcessMemory

SYNTAX BOOL ReadProcessMemory( HANDLE hProcess, // プロセスのハンドル LPCVOID lpBaseAddress, // 読み取り開始アドレス LPVOID buf, // データを格納するバッファ DWORD size, // 読むバイト数 LPDWORD lpNumberOfBytesRead // 読み取ったバイト数 ); DESC 指定されたプロセスのアドレス空間から指定された範囲のデータを 現在のプロセスの指定されたバッファへコピーします。 PROCESS_VM_READ アクセス権付きのハンドルを備えている任意のプロセスは この関数を呼び出せます。 通常は、デバッグ中のプロセスを読み取り対象にする。( それ以外にも使ってもよい。 ) POINT プロセスのハンドルは自身でも良いし、別のプロセスでも良い。 デバッガがデバッグ対象のプロセスの仮想メモリ空間の値を変更するために使う。
___

■ WriteProcessMemory

___

■ SetUnhandledExceptionFilter

SYNTAX LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER callback ); DESC Win32 が各スレッドとプロセスの最上位に置くトップレベル例外ハンドラを呼び出し元アプリケーションに置き換えます この関数の呼び出し後 デバッグ中でないプロセスで例外が発生し その例外が Win32 未処理例外フィルタに到着すると、 そのフィルタによって、callback で指定した例外フィルタ関数が呼ばれる。 コールバックされる関数は次のシグネーチャをもつ
    LONG CALLBACK SWFilter( EXCEPTION_POINTERS * );

















NINJAIDX 15