« 2003年8月 | トップページ | 2003年12月 »

2003年11月30日 (日)

ルートのConfig.MSIフォルダはなに?

MSインストーラーがインストールに使うテンポラリファイルを保存しとく場所です。
削除しちゃってもOKです。

| | コメント (0)

2003年11月25日 (火)

秀丸とVisual Studio .NETの連携方法

| | コメント (0) | トラックバック (0)

秀丸とVisual Studio .NETの連携方法

http://www.sofarts.com/oldnew/computer/env-soft/windows/app_programming/vs/net/hidemaru.htm

ここで出てくるvscmd.zipをコンパイルしてexeにしたもの。
vscmd_031125.zip
コンパイルしなくても、回答して出てきたvscmd.exeを秀丸のフォルダに放り込むだけで使えます。

| | コメント (0)

2003年11月24日 (月)

Cランタイムライブラリの関数で処理の所要時間を計るには。

clockを使います。

#include <stdio.h>
#include <time.h>

////////////////////////////////////////////////////////////////////////////////

void	a()
{
	for( int i = 0; i < 1000000000; ++i );
}

////////////////////////////////////////////////////////////////////////////////

void	b()
{
	for( int i = 0; i < 100000000; ++i );
}

////////////////////////////////////////////////////////////////////////////////

int	main()
{
	clock_t last = clock();
	a();
	double span = clock() - last;
	printf( "%f", span / CLOCKS_PER_SEC );

	last = clock();
	b();
	span = clock() - last;
	printf( "%f", span / CLOCKS_PER_SEC );

	return 0;
}

////////////////////////////////////////////////////////////////////////////////

| | コメント (0) | トラックバック (0)

Visual C++ 6.0でprofileが使えない。

プログラム中の関数の実行時間などを測れるプロファイラですが、VC6.0のプロファイラはバグまみれでなかなか使えません。




まず、メニューのビルド->プロファイルが無効になっているケース。
この場合は
HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\General
のProfilerInstalledキーに1が設定されているかどうかをチェックしよう。
ちなみにこれが有効にするためのレジストリファイル




次に、プロファイルを使うにはプロジェクトオプションを変更しなければなりません。

メニューのプロジェクト→設定→リンクタブ

このウインドウに「プロファイルを行う(&E)」というメニューがあるものの、チェックしてもプロファイルは有効にはなりません。
そこでプロジェクトオプションと云うフォームがあるのでそこに/profileと手書きで追加します。
(もしくはAlt+Eでもいいです。)

Ref: http://www.cmpt.phys.tohoku.ac.jp/~genya/vcprof.html

| | コメント (0)

「Windows Update エラー」となってアップデートできない。

パソコンの日付が狂ってるケースが多いのでチェックしてみましょう。

| | コメント (0)

メモリリークに関する考察。

new/deleteにまつわるメモリリークを検出しようと考えた。
new/deleteに関するメモリは全てスマートポインタであるPointerクラスで管理しているので、
Pointerクラスの機能としてメモリリークチェッカーを作ることにした。

newされたメモリは即座にPointerクラスのSetメソッドに渡される。これはPointerクラスの仕様。
そしてdeleteは全てPointerクラス内で行われる。

つまりSetメソッドに入ってきたアドレスとdelete直前のアドレスのログをとればメモリリークがあるかどうかチェックできる。
たとえばSetメソッドに入ってきたアドレスがdeleteされていなかったらメモリリークとなる。




が。C++には多重継承があるのでnewで返ったアドレスと、deleteに渡すアドレスがたとえ同じオブジェクトでも同一とは限らない。
このケースは確かに特殊で、多重継承していて、なおかつ基底クラスが仮想関数を持っていることが条件となる。
が、なんにせよアドレスが違ってしまうので単にnewのアドレスとdeleteのアドレスを==で比較して違っていたらメモリリーク、とは出来ない。


class	A
{
public:
	virtual ~A(){}
};
class	C
{
public:
	virtual ~C(){}
};
class	B :
	public A,
	public C
{};

int __stdcall	WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
	B*	pB = new B;
	A*	pA = pB;
	C*	pC = pB;

	//pAとpCはアドレスが異なる!!

	size_t b = sizeof(B);
	size_t c = sizeof(C);

	delete	pA;
}
このコードでは実際にそれを検証している。

以下がdelete文の直前でのウオッチウインドウである。







+ pA 0x00372f88 A *
+ pB 0x00372f88 B *
+ pC 0x00372f8c C *
b 8 unsigned int
c 4 unsigned int


pAとpBは等しいが、pBとpCが異なるのがわかると思う。

ここで注目したいのがbとcである。
B型とC型ではサイズが異なる。B型のほうが大きい。


|372f88-------------B:8-----------------|

+----+----+----+----+----+----+----+----+

			|372f8c----C:4------|
このようにBはCを含んでいる。

よくよく考えてみれば、Bは基底クラスであるAとCの情報を含んでいなければならない。そうでなければAとCに安全にキャストできない。
つまり「派生クラスの使用領域は基底クラスの使用領域を含む」と推論できる。多分そう外れてないと思う。




newされたオブジェクトをさらに派生した型に安全にアップキャストすることは出来ない。
つまりnewされたときの型より派生されることはない。=newされたときのオブジェクトの使用領域が最大である、といえる。
deleteするときにはそれと同じか、それより少ない領域となっている。また、その領域はnew時のものに含まれる。

これを利用すればメモリリークは検出できるだろう。…と思う。

| | コメント (0) | トラックバック (0)

_CrtSetDbgFlag

_CrtSetDbgFlagや_CrtCheckMemoryで_CRTDBG_CHECK_CRT_DFを使うと大量にメモリリークのログが出るけど、どうも自分のプログラムと関係がないっぽい。

ためしに、


#include <windows.h>
#include <crtdbg.h>

////////////////////////////////////////////////////////////////////////////////

int __stdcall	WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
	_CrtSetDbgFlag( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_CRT_DF );
	return 0L;
}

////////////////////////////////////////////////////////////////////////////////
上記のコードでやってみたんですが、結果は


Detected memory leaks!
Dumping objects ->
_file.c(137) : {42} crt block at 0x003707B0, subtype 0, 2048 bytes long.
 Data: < ~B	 B 0 B P B > F0 7E 42 00 10 7F 42 00 30 7F 42 00 50 7F 42 00
onexit.c(198) : {41} crt block at 0x00372EC8, subtype 0, 128 bytes long.
 Data: <  A		   > C3 10 41 00 CD CD CD CD CD CD CD CD CD CD CD CD
stdenvp.c(130) : {40} crt block at 0x00372BF8, subtype 0, 654 bytes long.
 Data: <_ACP_PATH=C:\Pro> 5F 41 43 50 5F 50 41 54 48 3D 43 3A 5C 50 72 6F
	:
stdenvp.c(117) : {4} crt block at 0x003716F0, subtype 0, 148 bytes long.
 Data: <  7 0 7	 7 ( 7 > C0 17 37 00 30 18 37 00 B8 18 37 00 28 19 37 00
stdargv.c(130) : {3} crt block at 0x00371648, subtype 0, 102 bytes long.
 Data: <P 7	   c:\docum> 50 16 37 00 00 00 00 00 63 3A 5C 64 6F 63 75 6D
ioinit.c(130) : {1} crt block at 0x00370670, subtype 0, 256 bytes long.
 Data: <		   > FF FF FF FF C1 0A CD CD FF FF FF FF C1 0A CD CD
Object dump complete.
はぁ?って感じですが。

どうもCラインタイムライブラリの段階でがっつりメモリリークしてるのかなぁ。
crtdbg.hってどーもしょぼしょぼみたいだし、_CrtSetDbgFlag周りのコードがバグってるのかも。
…まぁランタイムもデバッグツールもちゃんと動いててただの俺の勘違いの可能性がないわけじゃないですが…。

たぶんユーザーコードの問題じゃないと思います。
_CrtSetDbgFlagつかうなら_CRTDBG_CHECK_CRT_DFをはずして使うといいかも。

| | コメント (0)

2003年11月23日 (日)

C標準ライブラリを用いて、"02/07/18 14:16"といった任意のフォーマットの時間文字列を得るには?

#include <time.h>
#include <stdio.h>

{
	//timeでシステム時刻を得る。
	time_t	t = time( NULL );
	//localtimeでtm構造体を得る。
	/*
		struct tm
		{
			int tm_sec;	/* seconds after the minute - [0,59] */
			int tm_min;	/* minutes after the hour - [0,59] */
			int tm_hour;	/* hours since midnight - [0,23] */
			int tm_mday;	/* day of the month - [1,31] */
			int tm_mon;	/* months since January - [0,11] */
			int tm_year;	/* years since 1900 */
			int tm_wday;	/* days since Sunday - [0,6] */
			int tm_yday;	/* days since January 1 - [0,365] */
			int tm_isdst;	/* daylight savings time flag */
		};
	*/
	tm*	pTM = localtime( &t );

	//tm構造体のデータをsprintfに通して文字列にする。
	char	timeString[256];
	sprintf( timeString,  "%02d/%02d/%02d %02d:%02d",  pTM->tm_year%100, pTM->tm_mon, pTM->tm_mday, pTM->tm_hour, pTM->tm_min );
}

| | コメント (0)

« 2003年8月 | トップページ | 2003年12月 »