C/C++の最近のブログ記事

よく使う割りによく忘れるので、メモっておく。

%a

曜日の省略形。

%A

曜日の正式名。

%b

月の省略形。

%B

月の正式名。

%c

ロケールに対応する日付と時刻の表現。

%d

10 進数で表す月の日付 (01 ~ 31)。

%H

24 時間表記の時間 (00 ~ 23)。

%I

12 時間表記の時間 (01 ~ 12)。

%j

10 進数で表す年初からの日数 (001 ~ 366)。

%m

10 進数で表す月 (01 ~ 12)。

%M

10 進数で表す分 (00 ~ 59)。

%p

現在のロケールの午前/午後。

%S

10 進数で表す秒 (00 ~ 59)。

%U

10 進数で表す週の通し番号。日曜日を週の最初の日とする (00 ~ 53)。

%w

10 進数で表す曜日 (0 ~ 6、日曜日が 0)。

%W

10 進数で表す週の通し番号。月曜日を週の最初の日とする (00 ~ 53)。

%x

現在のロケールの日付表現。

%X

現在のロケールの時刻表現。

%y

10 進数で表す西暦の下 2 桁 (00 ~ 99)。

%Y

10 進数で表す 4 桁の西暦。

%z, %Z

タイム ゾーンの名前、または省略形。

%%

パーセント記号。


参考:

VC++で、デバッグ構成でビルドしたプログラムでは動作するコードが
リリース構成でビルドすると動かないよ?ということが稀にある。

これはVC++の最適化によるものかもしれない。

例えば、次のコード。

void func() {
    int a;
    a = 100;
}

この関数内の変数 a に値が代入されているが、
この値は全く使用されていない。

このとき、コンパイラはこの代入文をなかったものとして扱う。

つまり、上記関数は

void func() {
}
(何も処理なし)

と同じってこと。

この場合は当然そうだけど、
例えばSという構造体にaというメンバがあるとして、
この値がfunc2という関数にポインタ渡しして使用する場合

void func() {
    S _s;
    _s.a = 100;
    func2(&_s);
}

となるけど、この場合も最適化によって、
_s.a に代入された値は使用されていないとみなされて

void func() {
    S _s;
    func2(&_s);
}
(_s.a = 100 という行がなかったことになる)

と同じ処理になってしまう(ことがある!)

こういうのを避けたい場合、
あえて最適化させないプラグマを埋め込む。

#pragma optimize("", off)
(ここに最適化させたくないコード)
#pragma optimize("", on)

こうすると コンパイルで C4748 警告が出るけど、
当該コードがバッファオーバーランしないことが確実なら無視すれば良い。


参考: [MSDN] コードの最適化
http://msdn.microsoft.com/ja-jp/library/xz7ttk5s%28v=vs.80%29.aspx

MFC の CButton を継承して、マウスオーバーでイメージが切り替わるボタンをつくってみる。

MFC の CWnd を継承したクラスでカスタム描画処理を書きたい場合は、 OnPaint() (WM_PAINT のメッセージハンドラ) をオーバーライドするのだけど、 これを派生クラス側でオーバーライドすると、既定の描画処理が動かなくなってしまう。

これは、例えば、既定の描画処理の後に、その上からカスタム描画したい、 というような場合に困る。

そんなあなたに Default() メソッド。

void CCustomCtrl::OnPaint()
{
//CPaintDC dc(this); // device context for painting
// TODO: ここにメッセージ ハンドラー コードを追加します。
// 描画メッセージで CProgressCtrl::OnPaint() を呼び出さないでください。

Default();// ← これ!

// この下にいろいろ描画処理をすれば、既定クラスが描画した上から
// 自分の描画を書くことができる。

CClientDC dc(this);
CustomDraw(&dc);// 独自描画の実装。
}
sscanf() で数値拾って CTime とかに突っ込むか? とか考えてたけど、文字列から一発で日付型に変換する方法があった。

const CString strDate = _T("2011/02/01 00:00:00");

COleDateTime oleTime;
oleTime.ParseDateTime(strDate);

これで oleTime に結果が入る。

この COleDateTime は CTime にそのまま代入可能。


参考:
- COleDateTime クラス
- 日付と時刻 : オートメーションのサポート

VC++ で、例えば次のような書き方をしたとする。

class Test2;// 宣言

class Test1
{
public:
Test1();
~Test1();

Test2 m_test2; // ← Test2 をメンバに持たせる。
};

class Test2
{
public:
Test2();
~Test2();
};

すると、

error C2079: 'Test1::m_test2' が 未定義の class 'Test2' で使用しています。


というコンパイルエラーになる。

これは


class Test2;// 宣言

class Test1
{
public:
Test1();
~Test1();

Test2 *m_test2; // ← ポインタにする。
};

class Test2
{
public:
Test2();
~Test2();
};


とすればコンパイルは通る。

もしくは、Test2 を Test1 より先に書く。


参考: コンパイラ エラー C2079

Win32でDLLを明示的ロードするとき、LoadLibrary API関数を使用するのだけど、この引数に渡すDLLファイルのパスが正しいにも関わらず失敗(戻り値 0)することがある(フルパスで指定しても失敗する)。

引数に渡したDLLがあからさまに存在するのに失敗する場合、対象DLLが別のDLLを使用していて、そちらのロードに失敗している可能性がある。なので、対象DLLが使用しているDLLが存在するか調べる。

Visual Studio 付属ツールの dumpbin を使う。(Linux でいえば ldd みたいなやつ)

dumpbin /dependents hoge.dll

ここに表示されるDLLもちゃんと存在するか(パスが通っているか)確認する。

Visual C++ 2010 で MFC 拡張 DLL を作成して、同じく VC++ で作成した MFC アプリケーションからロードするとメモリリーク(解放漏れ)することがある。

DLL では特に何も処理していない。ウィザードで作成されたスケルトンをそのままビルドしただけのDLL。

それを LoadLibrary() して FreeLibrary() するだけで、VC++ がメモリリークを検出する。(2010 は特に何も設定しなくても解放漏れチェックしてくれるっぽい)

これが不思議でしょうがなかったのだけど、あるきっかけで、プロジェクトのプロパティで文字セットの設定を変えたらメモリリークしなくなった!

具体的には、プロジェクトのプロパティの文字コードの設定が、アプリケーション側は「マルチバイト文字セット」となっていて、DLL側は「Unicode文字セット」になっていた。DLL側の文字セットをマルチバイトにしたら、リークを検出しなくなった。

どうも、DLL と アプリケーション(exe)の文字コードの設定が異なっていると上手くないらしい。

結構ハマッてたのでメモしておく。

よくやるんだけど、よく忘れるのでメモ。

void func(int a);

の a は、普通の値渡し。
func() 内で引数を変更しても呼び出し元には影響しない。

void func(int *a);

の a はポインタ渡し。
func() 内で引数を変更すると呼び出し元にも反映される。

この場合、呼び出しは、

int x;
func(&x);

とし、func() 内で引数 a を変更する場合は、

*a = 0;

などとする。


void func(int &a);

の a は参照渡し。
func() 内で引数を変更すると呼び出し元にも反映される。

この場合、呼び出しは、

int x;
func(x);

とし、func() 内で引数 a を変更する場合は、

a = 0;

などとする。"&" や "*" はつけない。

VC++2010(Visual Studio 2010)で、以前のバージョンのVC++でつくられたDLLをリンクして起動すると、R6034というランタイムエラーが出ることがある。...というか出た。

状況としては、DLLとそのlibがあり、libを読み込んでコンパイル(ビルド)までは成功するが、DLLのロードをするときに実行時エラーになる感じ。

Runtime error!
Program:(モジュールのパス)\hoge.exe
R6034 An application has made attempt to load the C runtime library incorrectry.
Please contact the application's support team for more information

Google先生にきいてみると、

C ランタイム エラー R6034
アプリケーションがマニフェストを使用しないで C ランタイム ライブラリを読み込もうとしました。...云々

とある。

マニフェストの作り方もあったので、つくり直して再度コンパイルしてみるもNG。

もしかして、ランタイム自体がない?


実行時エラーといえばランタイムがないからエラーになる、というのはありがちな話。Visual Studioが入ってるんだからそれはないと思ってたんだけど、その先入観は捨てて、あえてランタイムを入れてみる。

ということで、そのDLLというのはVC2005で作られているらしいので、VC2005の再頒布パッケージというのをこのへんから落としてきてインストールしてみる。

しかし、状況変わらず。

むー。

そもそも、以前のバージョンのVCで作られたDLLは新しいバージョンのVC(でつくられたプログラム)では使えないのか?...そんなバカな。

バージョンの違いでランタイムも違う、というのはVBでもよくあったことなので、何が違うのか調べてみた。


ここによると、VC2005では msvcrt.lib をリンクすると msvcr80.dll というのを参照するらしい。VC2010の場合は 、同様に msvcrt.lib をリンクすると msvcr100.dll というのが参照されるらしい。つまり、VC2005とVC2010では、同じ msvcrt.lib をリンクしているつもりでも、その参照先のDLL(ランタイム)が違うということね。

さらにややこしいことに、VC2005 では msvcrt.lib は msvcrt.dll を参照し、その msvcrt.dll は msvcr80.dll にスルーしていて、VC2010 では msvcrt.lib は msvcr100.dll を直接参照しているっぽいこと。さらに、VC2010 では msvcrt.dll という名前のDLLも存在していて、しかしそれは VC2005のそれとは全く別物なのだそうです(このへん、私自身の中でも混乱していて正確じゃないかもしれませんが)。

なんだそりゃ!

つまり、今回エラーになってる DLL は、VC2005でいうところの msvcr80.dll を参照している為に、VC2010のランタイムと整合性が合わずエラーになってるってことか。でも、ダイナミックリンクしてるなら、そのDLLをVC2010で使えば2010のランタイムを使うんじゃないのか?

って、その問題のDLLをよーくみたら、サイズが 500KB 近くある。

これはもしかすると、VC2005のランタイムを静的リンクしてる(ランタイムごとDLLに入れこんでる)くさい?

ちょっと、VC2005とVC2010で以下のことを試した。

  • VC2005 の Release 構成でコンパイル → 正常動作
  • VC2005 の Debug 構成でコンパイル → ランタイムエラー
  • VC2010 の Release 構成でコンパイル → ランタイムエラー
  • VC2010 の Debug 構成でコンパイル → ランタイムエラー

VCのランタイムにはデバッグ用とリリース用の2つがあるんだけど、つまりこれはVC2005のリリース用ランタイムを静的リンクしてるDLLである疑いが強い。

これはDLLの製作元に問い合せてみるしかないか。

2017年2月

      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28        

アーカイブ

Powered by Movable Type 5.2.10