[C++/Windows] wstring/UTF16でエンコードされたファイルを読み込む

wstring の場合

#include <codecvt>
#include <iostream>
#include <locale>
#include <fstream>

int main()
{
    std::basic_ifstream<wchar_t> ifs("C:\\hoge1.txt", std::ios::binary);
    ifs.imbue(std::locale(
        ifs.getloc(), 
        new std::codecvt_utf16<wchar_t, 0x10ffff, std::codecvt_mode( std::little_endian |std::consume_header)>));

    std::vector<wchar_t> buf(100);
    ifs.read(buf.data(), 100);
    std::basic_string<wchar_t> istr(buf.data());
}

UTF16の場合

#include <codecvt>
#include <iostream>
#include <locale>
#include <fstream>

int main()
{
    std::basic_ifstream<uint16_t> ifs("C:\\hoge1.txt", std::ios::binary);
    ifs.imbue(std::locale(
        ifs.getloc(), 
        new std::codecvt_utf16<uint16_t, 0x10ffff, std::codecvt_mode( std::little_endian |std::consume_header)>));

    std::vector<uint16_t> buf(100);
    ifs.read(buf.data(), 100);
    std::basic_string<uint16_t> istr(buf.data());
}

[C++] プリコンパイルヘッダでビルド時間を短縮する

C++で開発するときにBoostを利用することも多いとおもうのですけど、Boostを利用するとビルド時間がかかるようになって大変です。何十ものソースコードで構成されたプロジェクトなんかで再ビルドしたときなんかはそのビルド時間に辟易してしまいます。

そこで役に立つのがプリコンパイ済みヘッダ(precommpiled header)です。プリコンパイル済みヘッダを利用するとコンパイル時間を大幅に短くできます。

Visual Studio 2015で新規のC++プロジェクトを作成した場合、デフォルトでプリコンパイル済みヘッダを利用するように設定されています。もし設定されているかどうか不安な場合には以下で確認できます。

プロジェクトの設定確認

  1. プロジェクト名を右クリックしPropertiesを選択、Project Property Pageを表示
  2. Configuration Property → C/C++ → Precompiled Header
  3. Precompile Header が “Use (/Yu)“となっているのを確認。
  4. Precompile Header File は “stdafx.h”(デフォル)
  5. Precompiled Header Ouput File は”$(IntDir)$(TargetName).pch”(デフォルト)

プレコンパイル用のファイルのプロパティの確認

こちらもプロジェクト作成時に自動的に作成されているはずですが念のため確認します。

  1. Header Filesに stdafx.h というヘッダファイルがあるのを確認する。なければ追加。この時点では空ファイルでもいい。
  2. Source Filesに stdafx.cppというソースファイルがあるのを確認。なければ追加。内容は以下のとおり。
    #include "stdafx.h"
  3. stdafx.cppを右クリックしてのPropertiesを選択しプロパティウィンドを開く
  4. Configuration Property → C/C++ → Precompiled Header
  5. Precompile Header が “Create (/Yc)“となっているのを確認。上の設定と違うので注意。

プレコンパイルするヘッダの指定

とりあえずプロジェクト側の設定は終わりました。(デフォルトで設定されてますが)
実際に以下のようなBoostをつかったコードをコンパイルしてみることにします。

#include "stdafx.h"
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;boost/thread/future.hpp&amp;gt;

void printHelloTask() {
	std::cout &amp;lt;&amp;lt; "Hello" &amp;lt;&amp;lt; std::endl;
}

int main() {

 	boost::unique_future&amp;lt;void&amp;gt; f1 =
 		boost::async(boost::launch::async, printHelloTask);
}

これをこのままコンパイルすると3秒かかります。

1>------ Build started: Project: MyProject, Configuration: Release Win32 ------
1>  MyProject.cpp
1>  Generating code
...
1>     3722 ms  ClCompile                                  1 calls
1>     3941 ms  Link                                       1 calls
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

※Visual Studioでビルド時間を表示するように変更するにはVisual Studioコンパイル時間を表示するを参照してください。

プレコンパイルするヘッダを指定する

時間がかかるヘッダをstdafx.hヘッダに追加します。ソースファイルのstdafx.cppの方ではないのでお間違いなく。
ここでは<boost/thread/future.hpp>を指定します。


#include <boost/thread/future.hpp>

ソース・ファイルのプロパティの確認

実際のプログラムを記載したソースファイルを作成すれば自動的に上で上記で作成されたプレコンパイル済みヘッダを利用することになっているはずですが、念のためソース・ファイルのプロパティを確認してプレコンパイル済みヘッダを使うようになっているか確認してみましょう。

  1. ソースファイル(MyProject.cpp)を右クリックしてのPropertiesを選択しプロパティウィンドを開く
  2. Configuration Property → C/C++ → Precompiled Header
  3. Precompile Header が “Use (/Yu)“となっているのを確認。こちらはまた Use です。

 

これで準備が終わったので再度コンパイルしてみます。

 

1>------ Build started: Project: MyProject, Configuration: Release Win32 ------
1>  MyProject.cpp
1>  Generating code
...
1>      593 ms  ClCompile                                  1 calls
1>     1903 ms  Link                                       1 calls
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

4秒近くかかっていたものが600ms程度(6倍)になりました! ソースファイルが多くなればなるほど効果が大きいのがおわかりになると思います。
ちなみにプレコンパイルヘッダ指定後最初のコンパイル時にはstdafx.cppがビルドされプレコンパイルヘッダ自身(*.pch)が作成されるのでこれには時間がかかります。以降のコンパイル時にはプレコンパイル済みヘッダが使われるのでソース・ファイル(MyProject.cpp)のコンパイルは早くなります。

[WinDbg/CDB] 不明なシンボル名をワイルドカードで検索する

例) USER32 モジュールにある(はず)の GetDC という文字がつく関数を探す

0:000> x user32!*getdc*
77d053c3 USER32!xxxBNGetDC = <no type information>
77d0c595 USER32!NtUserGetDCEx = <no type information>
77cf86c7 USER32!NtUserGetDC = <no type information>
77d1cfd9 USER32!LBGetDC = <no type information>

Windowsでダンプファイルを取得する

windbg のコマンドプロンプトからプロセスのダンプ(ミニダンプ)を取得できる

0:00> .dump /ma <ダンプのパス>

例)

0:00> .dump /ma C:\myapp.dmp

※ 「/ma」 はミニダンプを取得するオプション。
ちなみに「/f」はフルユーザーモードダンプを取得するオプションだが、名前に反してミニダンプの方が情報量は多いのでこちらを取るほうがよい。

[WinDbg/CDB] 特定のアドレスでブレークを仕掛けてメモリ値やレジスター値を変更する

0:00> bp 6d137998 "R eax = 1;g"

ダブルクォートの中に、ブレイク後に実行したいコマンドを書きます。最後の「;g」は 「再開」の指示です。

  • アドレス 6d137998 でブレークし、アドレス 6d137900 の値を 0x00ff に変更して再開する
0:00> bp 6d137998 "ew 6d137900 0x00ff;g"
  • 関数SomeFuncでブレークし、スタックを一行だけ表示して再開する
0:00> bp Module!SomeFunc "kvn 1;g"

「1」はスタックの行数を表しています。

[WinDbg/CDB] プロセスのトータルCPU時間を表示

0:00> .time
Debug session time: Mon Oct 19 10:38:47.000 2009 (GMT+9)
System Uptime: 0 days 1:28:25.006
Process Uptime: 0 days 0:12:56.000
  Kernel time: 0 days 0:00:17.000
  User time: 0 days 0:02:39.000

別の時間でダンプを取ることにより、その間にどれくらい CPU 時間を占有していたかを知ることもできる。

0:00> .time
Debug session time: Mon Oct 19 10:39:25.000 2009 (GMT+9)
                               ^^^^^^^^^ 38ms 後
System Uptime: 0 days 1:29:00.312
Process Uptime: 0 days 0:13:34.000
Kernel time: 0 days 0:00:18.000
                    ^^^^^^^^ 1秒
User time: 0 days 0:02:40.000
                  ^^^^^^^^^^^ 1秒

WinDgb/CDBでシンボルパスをセットする

ネットワークにつながっていれば以下のいずれかの設定でオンラインでシンボルを検索できます。以下に出てくる「C:\symbols」はネットワーク上からダウンロードしてきたシンボルファイルをローカルで保管しておく場所です。
パス名は任意ですがあらかじめ作成しておく必要があります。

  • 環境変数として設定する場合
  1. コントロールパネル->システム
  2. 「詳細設定タブ」
  3. 「環境変数」
  4. ユーザ環境変数、もしくはシステム環境変数の「新規」をクリックし、以下変数名と値をセット

    変数名 変数値
    _NT_SYMBOL_PATH SRV*C:\sybmols*http://msdl.microsoft.com/download/symbol
  1. File->Symbol File Path …
  2. テキストボックスに以下を入力
    SRV*C:\sybmols*http://msdl.microsoft.com/download/symbols
  • cdb 起動時にオプションでシンボルパスを設定する場合
C:\> cdb -y SRV*C:\symbols*http://msdl.microsoft.com/download/symbols 
  • cdb 起動後に .sympath コマンドを使ってシンボルパスを設定する場合
0:00> .sympath SRV*C:\symbols*http://msdl.microsoft.com/download/symbols

MS 以外から提供されているシンボルファイルをローカルで持ち、そちらも参照するようにしたい場合にはシンボルパスにセミコロン(;)で区切って指定することもできます。

0:00> .sympath C:\product\x64\Release;SRV*C:\symbols*http://sym.example.com/symbols;SRV*C:\symbols*http://msdl.microsoft.com/download/symbols -z