あかすくぱるふぇ

同人サークル「あかすくぱるふぇ」のブログです。

その他プログラミング

PMX(MMDモデル)ファイルビューワーの制作で必要になったので。

PMXファイル内の文字列はUTF-8とUTF-16のどちらかで書かれている。
どちらで書かれているかはヘッダで判断できる。
つまり、ヘッダに応じて、UTF-8とUTF-16のどちらで読むかの場合分けが必要となる。

その違いを吸収するための関数を作ってみた。
typedef std::basic_string<TCHAR, std::char_traits<TCHAR>, std::allocator<TCHAR> > tstring;

tstring read(std::ifstream& fileStream, const int size)
{
tstring str;

WCHAR wcharTmp[MAX_CHAR_LENGTH];
fileStream.read(reinterpret_cast<char*>(&wcharTmp), size);

// 終端文字付きの文字列を得るためにstringを利用。
// stringは終端文字を持たない代わりに、size()関数で文字列の長さを保持する。
// そして、c_str()で終端文字付の文字列配列を返す。
std::wstring wstr = wcharTmp;
wstr.resize(size / 2);
#ifdef _UNICODE
str = wstr;
#else
char charTmp[MAX_CHAR_LENGTH];
int multiByteSize = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, wcharTmp, -1, charTmp, multiByteSize, NULL, NULL);
str = charTmp;
str.resize(multiByteSize - 1);
#endif

return str;
}
参考ページ
http://d.hatena.ne.jp/sirocco/20130418/1366253252

個人的な備忘録として。

Visual Studioでは、Unicodeとマルチバイト文字に両対応するためのTCHARという型がある。
文字列を扱う時には基本的にTCHARを使うことになるが、

"1byteずつファイルから読み込みたい"
といった場合に以下のようにしてはいけない。

TCHAR hoge;
ifs.read(hoge, sizeof(TCHAR));
こうしてしまうと、
"マルチバイト文字セットを使用する場合は1バイトずつ、Unicode文字セットを使用する場合は2バイトずつ読み込む"
といった処理になってしまう。

1バイトずつ読み込みたいなら使用文字セットに関わらず、charを使う必要がある。

"リファクタリング-既存のコードを安全に改善する-"を読んだので、気になったところをまとめます。

・リファクタリングと機能追加の作業は区分すべき(p.54)
・コードの理解のためにリファクタリングする(p.56)
・インタフェースを変更した場合、古いインタフェースで新しいインタフェースを呼べばよい(p.64)
・リファクタリングを採用すれば、唯一無二の完璧な事前設計をする必要がなくなる(p.67)
・コメントが多い箇所はリファクタリングが必要である可能性が高い(p.77)
・機能追加の際はテストから書き始めよ(p.90)
・テストを書く際に、はじめは失敗するようにしておく(p.95)
・バグレポートを受け取ったら、そのバグを明らかにする単体テストを書く(p.97)
・テストをたくさん書こうとするな。一番妖しいと思う部分からテストせよ(p.97)
・継承のテストは全組み合わせではなく、各選択肢をテストすれば十分(p.101)
・メソッド名の長さは問題でない。メソッド本体との間の意味的な距離が重要(p.110)
・意味のあるメソッド名が思いつかなければ、メソッドは抽出しない(p.111)
・一時変数に値を設定するのは一度だけにすべき(p.128)
・一方があまり起こらない条件である条件分岐ではガード節を使う(p.250)
・switch文はポリモーフィズムに置き換える(p.255)
・例外は、正常処理とエラー処理を明確に分離する点でエラーコードよりも優れている(p.310)
・リファクタリングは何か別の目的を前提とし、その目的を達成するのに必要な分だけやればよい(p.360)

当たり前な人にとっては当たり前なんだろうけど、自分はずっと混乱してました。
「静的リンク、動的リンク、暗黙的リンク、明示的リンクってなんやねん」みたいな。
その辺の話がやっと理解できたっぽいので、備忘録として残しておこうと思います。

・前提
ライブラリは関数(と変数)の集合です。
関数は、関数名と関数の中身でできています。

・静的リンクと動的リンク
静的リンクはコンパイル時に関数名と関数の中身をリンクします。コンパイル後にライブラリの中身を変更できないので、「静的」と呼ばれます。
動的リンクは実行時に関数の中身をリンクします。コンパイル後にライブラリの中身を変更する余地が残っているので、「動的」と呼ばれます。

静的リンクでは、必ず.libファイルを使います。
コンパイル時にリンクすべき.libファイルを指定します。

一方、動的リンクでは、(Dynamic Link Libraryという名前の通り、)必ず.dllファイルを使います。
実行時にリンクすべき.dllファイルを参照します。

ここまでは比較的分かりやすい話だと思います。
難しいのが、動的リンクには、.libファイルを使う場合と使わない場合があるというところです。
それは、リンクする.dllファイルのファイル名や関数の関数名(以下、DLL情報と呼ぶ)を、呼び出し側の実行ファイルにどう埋め込むのかという点と関連します。

・明示的リンクと暗黙的リンク
.dllファイルを使うリンクには、明示的リンクと暗黙的リンクがあります。
明示的リンクとは、呼び出し側のプログラムのソースコードに、DLL情報を(明示的に)書くことによって、リンクする方式です。具体的には、LoadLibrary()やGetProcAddress()を用います。
一方、暗黙的リンクとは、呼び出し側のプログラムのソースコードにDLL情報を直接書かずに(暗黙的に)リンクする方式です。

暗黙的リンクでは、ソースコードにDLL情報を書かない代わりに、.libファイルをコンパイル時にリンクすることでDLL情報を実行ファイルに埋め込みます。
以上のような事情から、動的リンクには、.libファイルを使う場合と使わない場合があるのです。

・関連記事
http://akasuku.blog.jp/archives/68875230.html

↑このページのトップヘ