お知らせ

当ブログで使っているWordPressと言うシステム、何かバグって来たので入れ替えました。
どれくらいバグっているかと言うと、画像がアップできないくらい。
ついでにドメインも移行しました。
今後の更新は下記でやります。

http://yuxx.net

まぁ、サーバ同じなんでアレなんですが。。。

そんだけ。

Post to Twitter

関連する投稿

No Comments

「バック・トゥ・ザ・フューチャー 25thアニバーサリー Blu-ray BOX」発売決定!

バック・トゥ・ザ・フューチャー 25thアニバーサリー Blu-ray BOX [Blu-ray]

販売元:ジェネオン・ユニバーサル( 2010-10-26 )

定価:¥ 8,500

Amazon価格:¥ 6,234

時間:342 分

3 枚組 ( Blu-ray )


もう25周年なんだ・・・。
伝説的映画「バック・トゥ・ザ・フューチャー」のBlu-ray Boxが登場するなんて、めちゃくちゃうれしすぎる:D
やっぱ、この話って本当に類を見ないんだよね。
他と比較できないの、なんか。
あまりに「バック・トゥ・ザ・フューチャー」としての完成度が高すぎて、これの類似映画は思いつかないし、この映画のベースとなる映画も知らない。
ただ単に「バック・トゥ・ザ・フューチャー」としてしか認識できない。
そんな作品、珍しくない?

なんか、久々のBlogがただ勢いだけで書いてしまって申し訳ないけど、DVDコレクターズBoxを買えていない俺としては「これは買うしか!」と言う心境。
ちなみに、初回分にはブックレットがついてきて、それが無くなったら通常版として販売されるそうな。
それはそれでありがたい。

P.S.パトレイバーのDVDボックスも買えてないから、いっその事Blu-rayボックス出してくれないかなぁ?と思ってたら、出るじゃないか!

機動警察パトレイバー アーリーデイズ [Blu-ray]

販売元:バンダイビジュアル( 2010-07-23 )

定価:¥ 12,600 ( 中古価格 ¥ 7,452 より )

Amazon価格:¥ 9,326

時間:214 分

1 枚組 ( Blu-ray )



機動警察パトレイバー ON TELEVISION BD-BOX 1 [Blu-ray]

販売元:バンダイビジュアル( 2010-08-27 )

定価:¥ 33,600

Amazon価格:¥ 24,638

時間:600 分

3 枚組 ( Blu-ray )



機動警察パトレイバー ON TELEVISION BD-BOX2 <最終巻> [Blu-ray]

販売元:バンダイビジュアル( 2010-09-24 )

定価:¥ 33,600

Amazon価格:¥ 24,638

時間:550 分

3 枚組 ( Blu-ray )



機動警察パトレイバー NEW OVA BD-BOX [Blu-ray]

販売元:バンダイビジュアル( 2010-09-24 )

定価:¥ 27,300

Amazon価格:¥ 20,018

時間:400 分

3 枚組 ( Blu-ray )


そんだけ。

Post to Twitter

関連する投稿

, ,

No Comments

Quake IIIをVisual Studio 2008でビルド

id software(イド・ソフトウェア)、この会社は一人称視点のシューティングゲームをFirst Person Shooter通称FPSと言うジャンルとして広めた。
Wolfenstein 3Dを皮切りにDoomが欧米で大ヒット。
3D時代前夜にQuakeをリアルタイム3DCGでリリース。
少数精鋭主義を貫いたせいか、この前Bethesda Softworksかその親会社のZeniMaxに買収。
「洋ゲー=FPS」の様な状況を作り、今に至る。

で、id softwareは本当に素晴らしいソフト会社で、最新以外のQuakeシリーズのソースコードがGPLライセンスの元リリースされている。
例えばQuake 3はこれ。
ftp://ftp.idsoftware.com/idstuff/source/quake3-1.32b-source.zip
他にもDoom / Doom 2やHexen / Heretic、当然Quake、Quake IIもリリースされているので、興味があったらググってみてもいいかもしれない。

そしてそして、お待たせしました。
本題。
このソース、落として解凍してVCにぶち込んでビルドすれば動くのか?と言う話。
答えはNO!
なので記事に・・・。
で、「luozhiyu – Compile Quake III arena」を参考にやってみましょう、と。
あ、先に書いておくけどQuake 3 Arenaを持ってないと動かないからね!
未確認ながら、Demo版があるから、それでも出来るかも?
Amazonでもほぼ売り切れのようなものだから、Steamで買うという手もある。

と言う前置きはさておき、はじめましょうか。
まず普通に解凍する。
解凍したディレクトリに「code」と言うディレクトリがあるはず。
とりあえずそこを開く。
で、「quake3.sln」を開く。


バックアップは作らなくても良いと思う。
だって、そもそもZipファイルにフルソースがあるし・・・。


これもとりあえず無視して「OK」。

これも消しちゃってOKのはず。

これで変換終了。

履歴を出すとこんな感じ。

ここからコンパイル。
でもいろいろ設定しなきゃいけない。


まず、ソリューションのプロパティでスタートアッププロジェクトを「quake3」にする。

で、ウィンドウ上部中央にあるソリューションの構成が「Debug Alpha」とかの場合は「Debug」に変更する。


「quake3」のプロジェクトのプロパティを開いて、「デバッグ」、「コマンド引数」を

+set fs_cdpath "C:\Program Files\Quake III Arena\" +set r_mode "4"

とかにする。
ここのオプションはQuake3のインストールディレクトリにある「baseq3」ディレクトリにある「q3config.cfg」の設定内容と同様と思われる。
ただ一点違うのはプログラムやらアセットやらへのパス。
それを「fs_cdpath “インストールパス”」としないとゲームが起動しない。
あと、もう一つのオプションは解像度のオプションで、今使っているマシンはこのゲームが発売されて軽く10年は過ぎたくらいの時に組んだから、当時としては考えられないような解像度(1920 x 1200)なので、どうしてもエラーが出た。。
製品版から起動してもエラーが出たので、起動時の解像度を抑えるようにしてみた。
自分の環境ではフルスクリーンで落ちるので、「q3config.cfg」の

seta r_fullscreen "1"

seta r_fullscreen "0"

として抑えた。

ちなみに、ビルドして実行してみるとこんなエラーが出る。

これが出なくてオープニングムービーが始まってCDキーを入力する画面が出たらもう問題ないでしょう。

id softwareらしい無骨なタイトル画面w






こんな感じ。

お粗末。

Post to Twitter

関連する投稿

, , , , , , , , ,

No Comments

続・dprintf

前回「Visual CのGUIアプリで「出力」ウィンドウへデバッグメッセージを出す」でのdprintfは文字サイズ固定だったからちょっとどうかなぁ〜と思った次第。
多少は動的にして文字数に余裕を持たせたいところ。

あと、MSのAPIにはprintf_sとかsprintf_sとか、さらにはvsnprintf_sとか「_s」付きのセキュリティ強化版がある。
で、これ使ってエラー出すと完全に止まる。。。
例えばバッファより文字が多かった場合、即止まって怒られて落ちる。
本当はその後にバッファをより多くreallocする予定だったのにも関わらず・・・。
そしてそのエラーの止め方がわからない。。
なので、デバッグと言う名目なので、若干セキュアじゃないvsnprintfを使うことに。
(超後ろ向き。。。)
UNIX系でサポートされてない関数をバカスカ使うのも正直気が引けてたから、これで良いのだ〜♪
・・・なんてね。

とりあえず今回書いたコード。

// debug.h
#define _DPRINTF_MALLOC_ERR_ -100
#define _DPRINTF_ARG_ERR_ -101
#define _DPRINTF_REALLOC_ERR_ -102

int dprintf( const char *format, ...);
// debug.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "debug.h"

#define _DEBUG_BUFF_BASE_SIZE_ 256

int dprintf( const CHAR *format, ...)
{
	va_list argPtr;
	char *debugMsgBuffer;
	char *tmpMsgBuffer;
	int msgLen = 0;
	int maxBuffSize = _DEBUG_BUFF_BASE_SIZE_;

	va_start( argPtr, format );
	debugMsgBuffer = (char *) malloc( maxBuffSize );
	if ( debugMsgBuffer == NULL ) {
		OutputDebugStringA( "dprintf:malloc error.\n" );
		return _DPRINTF_MALLOC_ERR_;
	}

	if ( format == NULL ) {
		OutputDebugStringA( "dprintf:format argument is null.\n" );
		return _DPRINTF_ARG_ERR_;
	}

	msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
	// vsnprintfにてバッファ終端に'\0'が書き込まれない
	// 時があったので、strlenでも長さチェックをかける。
	// あるいは、この時点でスタックを破壊している可能性もある。
	if ( (int) strlen( debugMsgBuffer ) > msgLen ) msgLen = -2;

	// メモリが足りないときの処理
	while ( msgLen < 0 ) {
		maxBuffSize += _DEBUG_BUFF_BASE_SIZE_;
		tmpMsgBuffer = (char *) realloc( debugMsgBuffer, maxBuffSize );
		if ( tmpMsgBuffer == NULL ) {
			free( debugMsgBuffer );
			OutputDebugStringA( "dprintf:realloc error.\n" );
			return _DPRINTF_REALLOC_ERR_;
		}
		debugMsgBuffer = tmpMsgBuffer;

		msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
		// vsnprintfの'\0'書き忘れ問題をここでも対処。
		if ( (int) strlen( debugMsgBuffer ) > msgLen ) msgLen = -2;
	}

	OutputDebugString( debugMsgBuffer );
	free( debugMsgBuffer );

	return msgLen;
}

まぁ、コメントの通りなんだけど、

if ( (int) strlen( debugMsgBuffer ) > msgLen ) msgLen = -2;

なんてい言う小賢しい処理を入れてる。
何でかというと、下記のコードを実行してもらいたい。

vsnprintfでおかしくなる。

// debug.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "debug.h"

#define _DEBUG_BUFF_BASE_SIZE_ 4

int dprintf( const CHAR *format, ...)
{
	va_list argPtr;
	char *debugMsgBuffer;
	char *tmpMsgBuffer;
	int msgLen = 0;
	int maxBuffSize = _DEBUG_BUFF_BASE_SIZE_;

	char test[1024];
	int testLen = 0;

	setlocale( LC_ALL, "C" );

	va_start( argPtr, format );
	debugMsgBuffer = (char *) malloc( maxBuffSize );
	if ( debugMsgBuffer == NULL ) {
		OutputDebugStringA( "dprintf:malloc error.\n" );
		return _DPRINTF_MALLOC_ERR_;
	}

	if ( format == NULL ) {
		OutputDebugStringA( "dprintf:format argument is null.\n" );
		return _DPRINTF_ARG_ERR_;
	}

	msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
	// vsnprintfにてバッファ終端に'\0'が書き込まれない
	// 時があったので、strlenでも長さチェックをかける。
	// あるいは、この時点でスタックを破壊している可能性もある。
	// if ( strlen( debugMsgBuffer ) > msgLen ) msgLen = -2; // ここをコメントアウト
	// メモリが足りないときの処理
	while ( msgLen < 0 ) {
		{ // debug
			testLen = sprintf( test, "maxBuffSize appended from \"%d\" to", maxBuffSize );
			maxBuffSize += _DEBUG_BUFF_BASE_SIZE_;
			sprintf( &test[testLen], "\"%d\".\n", maxBuffSize );
			OutputDebugStringA( test );
		} // debug end
		tmpMsgBuffer = (char *) realloc( debugMsgBuffer, maxBuffSize );
		if ( tmpMsgBuffer == NULL ) {
			free( debugMsgBuffer );
			OutputDebugStringA( "dprintf:realloc error.\n" );
			return _DPRINTF_REALLOC_ERR_;
		}
		debugMsgBuffer = tmpMsgBuffer;

		msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
		{ // debug
			sprintf( test, "maxBufferSize = \"%d\"\n msgLen = \"%d\"\n  strlen( debugMsgBuffer ) = \"%d\"\n", maxBuffSize, msgLen, strlen( debugMsgBuffer ) );
			OutputDebugStringA( test );
		} // debug end
		// vsnprintfの'\0'書き忘れ問題をここでも対処。
		// if ( strlen( debugMsgBuffer ) > msgLen ) msgLen = -2; // ここをコメントアウト
	}

	OutputDebugString( debugMsgBuffer );
	free( debugMsgBuffer );

	return msgLen;
}

さっきの小賢しいコード2カ所を撤去してメモリを何バイト取得し、文字列の長さはいくらで、実際の文字列の長さはいくらかを表示しているコードも入ってる。
これを額面通り

dprintf( "hoge = %5d\n", hoge );

とか文字数を変えて実行してみると、変な文字が付いてくる可能性がある。
自分の環境では

glnWidth =  1432	glnHeight =   815

を期待したところ、

glnWidth =  1432	glnHeight =   815
ォォォォォォォォォ

と言うようなゴミが付いてきた。
どうやら境界線ギリギリで書き込みを行う場合に’\0′が書き込まれていないような気もする。
とは言え、vsnprintfの第2引数を-1から-2に変えたところで同様のエラーが起きる。
個人的には手詰まり。
なので、本当に文字処理をプログラム中で扱うときはこの関数は使えない。。。
対処できないし、こんなの。
strlenによるネガティブな対処で良ければいくらでもやるけど、これ、正解じゃないよね?
そんなわけで、dprintfは前のバージョンの法が良かったのかもしれないと思えてきたり・・・。
(で、でも、文字数制限は無いぞ!と、自分を擁護しつつ、こちらを改良して行くことに。。。)

お粗末。

Post to Twitter

関連する投稿

, , , , , ,

No Comments

Oblivion日記 その1

いやぁ~、空気がうまい!
あ、ゲーム内の話だけれども。。。
ちょいと画質調整をしつつ、景観を撮ってみました。



もう眺めが良すぎてサイコ~。

とか言ってたら、アイテムが貯まって貯まってつらくなってきた。
スキル設定を大幅にミスったため、未だレベル2・・・。
で、Imperial Cityのボロ屋を買うことにしたんだけど、ど~にもお金が足りません、と。
あのボロ屋が2000もするなんておかしい!
あの商店街のババァ、いつかぶった切ってやる:P





け、調子の良いババァだぜ。
と言うわけで、一応家を買うことに。
てか、めちゃくちゃスクリーンショット撮ったのに、保存されていないものがある。。
外部のスクリーンショット京アプリが全部動かないし・・・。
Steam版だけ?
まぁ、いっか?





「何者だ?」とか言われても、しがないダークエルフですよとしか言いようがない。

で、コロールにも着いた。

そして愛しのは虫類系アイドル ダ・ルマにも遭遇。

まぁ、既にさらわれているわけですが。。。

とりあえずそんな感じ。
帝都の商店問題も解決したんだけど、スクリーンショットが途切れ途切れで載せる気無くした。。。

そんなかんじ。

The Elder Scrolls IV: Oblivion Game of the Year Edition(輸入版:北米)

The Elder Scrolls IV: Oblivion Game of the Year Edition(輸入版:北米)

中古価格: ¥ 10,401 より

Amazon価格:¥ 2,360

カテゴリ:DVD-ROM


Post to Twitter

関連する投稿

, ,

No Comments

Visual CのGUIアプリで「出力」ウィンドウへデバッグメッセージを出す

俺、PHPerの頃からの癖で、デバッグメッセージをどうしても出したくなる。
コマンドライン上では普通にprintfではき出せば良いんだけど、GUIとなるとそこに出すのもちょいと面倒だし、メッセージボックスなんてやった日には、メッセージボックスの嵐となる可能性さえ秘めているのは自明。
で、Visual Studioでデバッグすると出力ウィンドウがあります、と。
これを使いたい。
答えを書いちゃうとwindows.hにある、OutputDebugStringA( *str )と言う関数で実現可能です、と。
と言うわけで、dprintfを自作。

// debug.h
bool dprintf( const char *str, ...);
// debug.cpp
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>

#define _DEBUG_OUT_BUFF_SIZE_ 128

bool dprintf( const char *str, ...)
{
	char debugOutBuff[ _DEBUG_OUT_BUFF_SIZE_ ];

	va_list ap;
	va_start( ap, str );

	if ( !vsprintf_s( debugOutBuff, _DEBUG_OUT_BUFF_SIZE_, str, ap ) ) {
		OutputDebugStringA( "dprintf error." );
		return false;
	}
	OutputDebugStringA( debugOutBuff );

	return true;
}

dprintfで「出力」ウィンドウへ出力したところ

まぁ、クソみたいな関数だけど、一応メモ。
使い方はまぁ、printfと同じだと思ってもらえれば。
あと、OutputDebugStringではなく、何故OutputDebugStringAを使っているかというと、「出力」ウィンドウがShift_JISだったからと言う。。。
少なくとも俺の持ってるVisual Studio 2008 Professionalはそうなってた。
OutputDebugStringを指定しておくとプロジェクトがUnicodeを使うように指定されていると、コンパイル時にOutputDebugStringWと言うUnicode版に書き換わってしまって都合が悪いかなぁ、と。
VC2010の「出力」ウィンドウがUnicodeになってるんだったらifdef使うなり拡張はするかも。

そんだけ。

んが、「続・dprintf」に続く。

Post to Twitter

関連する投稿

, , , , , ,

No Comments

メモリのアラインメントを確認する

そもそもの話。
なぜ「ゲームプログラマになる前に覚えておきたい技術(以下「セガ本」)」を読んでる途中で「C言語ポインタ完全制覇(以下「ポインタ本」)」を読むことになったか?
それは、セガ本にデータ型のサイズで割りきれるアドレスでデータを読み込まないと、x86系(いわゆるIntel、AMD系)以外のCPUではクラッシュし、x86でもデータを2回読むことになってパフォーマンスが落ちる、と書いてあったから。
で、パッと見て理解できないでいたら、時を同じくしてポインタ本が届き、目次にアラインメントの記述が。
と言うわけで、ポインタ本を読み進めてみた次第。

そこで思ったのが、この本、本当に為になる。
俺みたいなCの見習いの肩もみの家の便所掃除みたいな人間にはいろいろ発見が多すぎて驚く。
例えば

#include <stdio.h>

int main()
{
    int i;
    char s[] = "abcdefghij";

    for ( i = 0; i < sizeof( s ) - 1; ++i ) {
        printf( "%d:%c\n", i, i[s] );
    }
}

なんてコード。
実行するとこう。

McLaren% gcc -o pointer_test pointer_test.c
McLaren% ./pointer_test
0:a
1:b
2:c
3:d
4:e
5:f
6:g
7:h
8:i
9:j

9行目のi[s]はs[i]の間違いと思いがちだけど、”これでも”問題ない。
出来るか出来ないかの話であって、常識的にこの書き方をして良いかは別の話(そしてもちろんダメ)。
この表記はコンパイル時に

printf( "%d:%c\n", i, *( i + s ) );

と変換しているだけ。
確かにポインタ+数値でそのポインタの型の分だけ先へ進む機能がある。
とまぁ、なかなか興味深い。

さてさて本題。
ようやくアラインメントが書いてあるページまでたどり着いた。
どうやら現代のコンパイラはかなりその辺りも配慮しているらしく、次に置かれるデータがそのデータ型で割り切れない場合、”詰め物”をしてくれるんだとか。
実際コードにして試してみまふ。

// alignment_check.c
#include <stdio.h>

typedef struct {
    char ch;
    double dn;
    short sn;
    int nu;
} MyStruct;

int main()
{
    MyStruct hoge;
    unsigned long gap1, gap2, gap3;

    printf( "sizeof char\t%lu\n", sizeof( char ) );
    printf( "sizeof double\t%lu\n", sizeof( double ) );
    printf( "sizeof short\t%lu\n", sizeof( short ) );
    printf( "sizeof int\t%lu\n\n", sizeof( int ) );

    printf( "sizeof MyStruct\t%lu\n\n", sizeof( MyStruct ) );

    printf( "\t&hoge's hexadecimal memory address.\n" );
    printf( "\tname\t\ttype\t\taddress\t\tsize\n" );
    printf( "\t&hoge\t\tMyStruct\t%p\t%4lu\n", &hoge, sizeof( hoge ) );

    printf( "\t&hoge.ch\tchar\t\t%p\t%4lu\n", &hoge.ch, sizeof( hoge.ch ) );
    gap1 = (unsigned long)&hoge.dn -
        ( (unsigned long)&hoge.ch + sizeof( hoge.ch ) );
    printf( "gap1:%lu\n", gap1 );

    printf( "\t&hoge.dn\tdouble\t\t%p\t%4lu\n", &hoge.dn, sizeof( hoge.dn ) );
    gap2 = (unsigned long)&hoge.sn -
        ( (unsigned long)&hoge.dn + sizeof( hoge.dn ) );
    printf( "gap2:%lu\n", gap2 );

    printf( "\t&hoge.sn\tshort\t\t%p\t%4lu\n", &hoge.sn, sizeof( hoge.sn ) );
    gap3 = (unsigned long)&hoge.nu -
        ( (unsigned long)&hoge.sn + sizeof( hoge.sn ) );
    printf( "gap3:%lu\n", gap3 );

    printf( "\t&hoge.nu\tint\t\t%p\t%4lu\n\n", &hoge.nu, sizeof( hoge.nu ) );

    printf( "char + gap1 + double + gap2 + short + gap3 + int = %lu\n\n",
            sizeof( char ) + gap1 +
            sizeof( double ) + gap2 +
            sizeof( short ) + gap3 +
            sizeof( int ) );

    printf( "&hoge's decimal memory address (with alighnment gap size).\n" );
    printf( "\tname\t\ttype\t\taddress\t\tsize\n" );
    printf( "\t&hoge\t\tMyStruct\t%ll\t%4lu\n", &hoge, sizeof( hoge ) );

    printf( "\t&hoge.ch\tchar\t\t%lu\t%4lu\n", &hoge.ch, sizeof( hoge.ch ) );
    printf( "gap1:%lu\n", gap1 );

    printf( "\t&hoge.dn\tdouble\t\t%lu\t%4lu\n", &hoge.dn, sizeof( hoge.dn ) );
    printf( "gap2:%lu\n", gap2 );

    printf( "\t&hoge.sn\tshort\t\t%lu\t%4lu\n", &hoge.sn, sizeof( hoge.sn ) );
    printf( "gap3:%lu\n", gap3 );

    printf( "\t&hoge.nu\tint\t\t%lu\t%4lu\n", &hoge.nu, sizeof( hoge.nu ) );

    return 0;
}

まぁ、こんだけ親切に情報盛ったから、アドレス表記だけで良いとは思ったけど、一応アドレスを10進数にしたやつも記載。
(つっても、64ビット環境においてunsigned long程度でアドレス表示して間に合わない気がするけど、ギャップを目視することが目的だから、あえてこのまま。
あれ?ラップトップのMacでgcc動かしたときって64ビット扱い?
・・・ま、今回は気にしないことに。
どうせテストだし。。。
まともに64ビットアドレス書いてたら、京単位らしいから・・・ね。)

で、結果。

McLaren% gcc -o alignment_check alignment_check.c
alignment_check.c: In function ‘main’:
alignment_check.c:48: warning: format ‘%lu’ expects type ‘long unsigned int’, but argument 2 has type ‘struct MyStruct *’
alignment_check.c:49: warning: format ‘%lu’ expects type ‘long unsigned int’, but argument 2 has type ‘char *’
alignment_check.c:52: warning: format ‘%lu’ expects type ‘long unsigned int’, but argument 2 has type ‘double *’
alignment_check.c:55: warning: format ‘%lu’ expects type ‘long unsigned int’, but argument 2 has type ‘short int *’
alignment_check.c:58: warning: format ‘%lu’ expects type ‘long unsigned int’, but argument 2 has type ‘int *’
McLaren% ./alignment_check
sizeof char     1
sizeof double   8
sizeof short    2
sizeof int      4

sizeof MyStruct 24

        &hoge's hexadecimal memory address.
        name            type            address         size
        &hoge           MyStruct        0x7fff5fbfef10    24
        &hoge.ch        char            0x7fff5fbfef10     1
gap1:7
        &hoge.dn        double          0x7fff5fbfef18     8
gap2:0
        &hoge.sn        short           0x7fff5fbfef20     2
gap3:2
        &hoge.nu        int             0x7fff5fbfef24     4

char + gap1 + double + gap2 + short + gap3 + int = 24

&hoge's decimal memory address (with alighnment gap size).
        name            type            address         size
        &hoge           MyStruct        140734799802128   24
        &hoge.ch        char            140734799802128    1
gap1:7
        &hoge.dn        double          140734799802136    8
gap2:0
        &hoge.sn        short           140734799802144    2
gap3:2
        &hoge.nu        int             140734799802148    4

こんな塩梅。
ワーニングは全部アドレスを無理矢理10進数で出したため。
「ポインタ本」と同じように構造体で確認した。
こうすれば普通の処理系では間に別の変数を入れたりする余地はあるまい:-)
で、確かにアドレスを次のメンバ変数のサイズで割り切れない場合、ギャップが出ている。
なるほど、こうすればどのCPUでもスマートに動くというわけですかい。
勉強になった。

C言語ポインタ完全制覇 (標準プログラマーズライブラリ)

著者/訳者:前橋 和弥

出版社:技術評論社( 2001-01 )

定価:¥ 2,394

Amazon価格:¥ 2,394

単行本 ( 323 ページ )

ISBN-10 : 4774111422

ISBN-13 : 9784774111421



ゲームプログラマになる前に覚えておきたい技術

著者/訳者:平山 尚(株式会社セガ)

出版社:秀和システム( 2008-11-15 )

定価:¥ 4,725

Amazon価格:¥ 4,725

単行本 ( 872 ページ )

ISBN-10 : 4798021180

ISBN-13 : 9784798021188


Post to Twitter

関連する投稿

, , , ,

No Comments

スタックオーバーフローをテスト

最近、「C言語ポインタ完全制覇 (標準プログラマーズライブラリ)」という本を読んでる。
タイトルの通り、C言語の、それもポインタだけに的を絞った本。
これがなかなかどうして面白くて、文字も大きいのですらすら進んでしまう。
ただ、簡単かと言われれば全く違って、興味深くて考えさせられるような話題ばかり。

ようやく100ページまで進んだ。
そしたらセキュリティーホールの温床になると言うスタックオーバーフローをテストしようという楽しいコードが書いてあった。
で、試したくなるじゃないですか。
若干情報多めに書いて写経してみたのが下記。

// stack_overflow_test.c
#include <stdio.h>

void hello()
{
    static int i = 0;

    fprintf( stderr, "stderr:\tHello xD\n" );
    printf( "\tNo.%d Hello:P\n", i++ );
}

void func()
{
    void        *buf[10];
    static int  i;

    printf( "buf\t%p\n*buf\t%p\n&i\t%p\n&hello\t%p\n\n", buf, *buf, &i, &hello );

    for ( i = 0; i < 16; ++i ) {
        buf[i] = hello;
        printf( "buf[%d]\t%p\n", i, &buf[i] );
    }

    printf( "\n\tEnd of func()\n\n" );
}

int main()
{
    int buf[1000];

    printf( "Start\n\n" );
    func();
    printf( "End\n\n" );

    return 0;
}

で、実行するとこう。

% gcc -o stack_overflow_test stack_overflow_test.c
% ./stack_overflow_test
Start

buf     0x7fff5fbfdf20
*buf    0x100000eee
&i      0x10000108c
&hello  0x100000d1c

buf[0]  0x7fff5fbfdf20
buf[1]  0x7fff5fbfdf28
buf[2]  0x7fff5fbfdf30
buf[3]  0x7fff5fbfdf38
buf[4]  0x7fff5fbfdf40
buf[5]  0x7fff5fbfdf48
buf[6]  0x7fff5fbfdf50
buf[7]  0x7fff5fbfdf58
buf[8]  0x7fff5fbfdf60
buf[9]  0x7fff5fbfdf68
buf[10] 0x7fff5fbfdf70
buf[11] 0x7fff5fbfdf78
buf[12] 0x7fff5fbfdf80
buf[13] 0x7fff5fbfdf88
buf[14] 0x7fff5fbfdf90
buf[15] 0x7fff5fbfdf98

        End of func()

zsh: segmentation fault  ./stack_overflow_test

あれ~?
hello()が実行されてない・・・??
と言うわけで、落ちる前に一度hello()を呼んでみた。

#include <stdio.h>

void hello()
{
    static int i = 0;

    fprintf( stderr, "stderr:\tHello xD\n" );
    printf( "\tNo.%d Hello:P\n", i++ );
}

void func()
{
    void        *buf[10];
    static int  i;

    printf( "buf\t%p\n*buf\t%p\n&i\t%p\n&hello\t%p\n\n", buf, *buf, &i, &hello );
    hello();

    for ( i = 0; i < 16; ++i ) {
        buf[i] = hello;
        printf( "buf[%d]\t%p\n", i, &buf[i] );
    }

    printf( "\n\tEnd of func()\n\n" );
}

int main()
{
    int buf[1000];

    printf( "Start\n\n" );
    func();
    printf( "End\n\n" );

    return 0;
}

するとこうなる。

% gcc -o stack_overflow_test stack_overflow_test.c
Start

buf     0x7fff5fbfdf20
*buf    0x100000eee
&i      0x10000108c
&hello  0x100000d10

stderr: Hello xD
        No.0 Hello:P
buf[0]  0x7fff5fbfdf20
buf[1]  0x7fff5fbfdf28
buf[2]  0x7fff5fbfdf30
buf[3]  0x7fff5fbfdf38
buf[4]  0x7fff5fbfdf40
buf[5]  0x7fff5fbfdf48
buf[6]  0x7fff5fbfdf50
buf[7]  0x7fff5fbfdf58
buf[8]  0x7fff5fbfdf60
buf[9]  0x7fff5fbfdf68
buf[10] 0x7fff5fbfdf70
buf[11] 0x7fff5fbfdf78
buf[12] 0x7fff5fbfdf80
buf[13] 0x7fff5fbfdf88
buf[14] 0x7fff5fbfdf90
buf[15] 0x7fff5fbfdf98

        End of func()

stderr: Hello xD
        No.1 Hello:P
stderr: Hello xD
        No.2 Hello:P
stderr: Hello xD
        No.3 Hello:P
stderr: Hello xD
        No.4 Hello:P
stderr: Hello xD
        No.5 Hello:P
zsh: segmentation fault  ./stack_overflow_test

これでしっかり動いた。
5回勝手(不正)に実行されちょる。

本の説明によるとメモリの状態は下記のような感じとなるらしい。
–ここ移行に別の変数が追加されていく–
buf[0] 0x7fff5fbfdf20
buf[1] 0x7fff5fbfdf28
buf[2] 0x7fff5fbfdf30
buf[3] 0x7fff5fbfdf38
buf[4] 0x7fff5fbfdf40
buf[5] 0x7fff5fbfdf48
buf[6] 0x7fff5fbfdf50
buf[7] 0x7fff5fbfdf58
buf[8] 0x7fff5fbfdf60
buf[9] 0x7fff5fbfdf68
==他の自動変数==
==関数終了時に戻るアドレス情報など==
==その他の領域==

考察:buf[10]~buf[15]までの6個分余分に配列があると仮定して上がいてます、と(・・アレ?5回しか実行されてない??)。
自動変数を食い破り、呼び出し元の関数情報を破壊して行きます、と。
あ、わかった。。。
funcに自動変数iがあるから1回少ないんだ。
funcをこう変えた。

void func()
{
    void        *buf[10];
    static int  i;
    int a, b, c, d, e; // 追加

    printf( "buf\t%p\n*buf\t%p\n&i\t%p\n&hello\t%p\n\n", buf, *buf, &i, &hello );
    hello();

    for ( i = 0; i < 15; ++i ) {
        buf[i] = hello;
        printf( "buf[%d]\t%p\n", i, &buf[i] );
    }

    printf( "\n\tEnd of func()\n\n" );
}

結果はこう。
(ちなみに、ちょっとプログラムいじっちゃったからアドレスと表記が若干違う。。)

Start

&func   0x100000d3f
buf     0x7fff5fbfeea0
*buf    0xffffffffffffffff
&i      0x10000108c
&hello  0x100000cf8

stderr: Hello xD
        No.0 Hello:P
buf[0]  0x7fff5fbfeea0
buf[1]  0x7fff5fbfeea8
buf[2]  0x7fff5fbfeeb0
buf[3]  0x7fff5fbfeeb8
buf[4]  0x7fff5fbfeec0
buf[5]  0x7fff5fbfeec8
buf[6]  0x7fff5fbfeed0
buf[7]  0x7fff5fbfeed8
buf[8]  0x7fff5fbfeee0
buf[9]  0x7fff5fbfeee8
buf[10] 0x7fff5fbfeef0
buf[11] 0x7fff5fbfeef8
buf[12] 0x7fff5fbfef00
buf[13] 0x7fff5fbfef08
buf[14] 0x7fff5fbfef10

        End of func()

End

zsh: segmentation fault  ./stack_overflow_test

ほら、実行されない。
ただ不思議なことに、

int a;

だけにした場合と、

int a, b, c, d;

までにした場合、

Start

&func   0x100000d3f
buf     0x7fff5fbfeeb0
*buf    0x7365745f776f6c66
&i      0x10000108c
&hello  0x100000cf8

stderr: Hello xD
        No.0 Hello:P
buf[0]  0x7fff5fbfeeb0
buf[1]  0x7fff5fbfeeb8
buf[2]  0x7fff5fbfeec0
buf[3]  0x7fff5fbfeec8
buf[4]  0x7fff5fbfeed0
buf[5]  0x7fff5fbfeed8
buf[6]  0x7fff5fbfeee0
buf[7]  0x7fff5fbfeee8
buf[8]  0x7fff5fbfeef0
buf[9]  0x7fff5fbfeef8
buf[10] 0x7fff5fbfef00
buf[11] 0x7fff5fbfef08
buf[12] 0x7fff5fbfef10
buf[13] 0x7fff5fbfef18
buf[14] 0x7fff5fbfef20

        End of func()

stderr: Hello xD
        No.1 Hello:P
stderr: Hello xD
        No.2 Hello:P

となる。
エラーは起きない。
けど変。

結論:戻り先アドレスまで上がいたら、そこにある情報を実行しちゃいました、的な感じの認識。

まぁ、何にせよ、バッファが溢れないように注意しないといつか痛い目見ますよ、と。
精進します。

C言語ポインタ完全制覇 (標準プログラマーズライブラリ)

著者/訳者:前橋 和弥

出版社:技術評論社( 2001-01 )

定価:¥ 2,394

Amazon価格:¥ 2,394

単行本 ( 323 ページ )

ISBN-10 : 4774111422

ISBN-13 : 9784774111421


Post to Twitter

関連する投稿

, , , ,

No Comments

今さらPC版のOblivionをはじめる、の巻

洋ゲーファンには欠かせないPCゲーム配信ソフトSteam。
第一弾ソフトのHalf-Life2が欲しくてアカウントは持っているわけ。
とは言え、それ以降特に欲しいソフトもなく、Half-Life2のエピソードばら売りに反感を覚え、そして何よりデスクトップPCがショボ過ぎたために塩漬け状態に。

そんなある日、開発目的のためにグラフィックスボードを入れようと思い立って入れてみたら、Half-Life2もフルオプションで普通に動くし、意外と行けることがわかった。
で、ですよ。
PS3で久々にはまったゲームThe Elder Scrolls IV:Oblivionがあると聞いて早速アクセス。
が、日本アカウントからだと何故か買えないという悲しいお知らせ。
いろいろ調べてブラウザ上から米国アカウントとしてカートに入る。
(http://store.steampowered.com/?cc=us←ここから「oblivion」で検索。)
今度は日本アカウントとしてアクセスしてさらにログインをします、と。
(http://store.steampowered.com/?cc=jp←この画面から右上のログインを押してログイン。アカウント持ってない人はそこで普通に登録して下さい。クレジットカード使うので、変なアカウントだとカードごと止められるかもしれないので、本当に普通に登録して下さいw)
そしてWeb上でお会計を済ませてSteamを起動してダウンロードしたら、なんとなんと、無事に買えました!とさ。
しかも、大特価で大体$24.99。
全部入りのGame of the Year Editionと呼ばれるセットで、パッケージ版には含まれていないDLC(ダウンロード・コンテンツ)込み。
Amazonとかで頼むよりも安い。
しかも即日DL。。

スゴイ時代になりました。
でもねぇ、趣味に充てる時間を削ってまで勉強するため仕事も辞めたのに、これで良いのかと・・・。
Oblivion、マジでやりまくってたんですよ。。。
Xbox360のコントローラーを設定したりもしたけど、やっぱりPC版はキーボード・マウスでやるように出来ているから、結局あきらめることに。
どうせFPSモードでしか遊んでなかったから、大して問題ないんだけどね。

さてさて、肝心のゲーム画面はと言うと、4年前のゲームとは思えない!の一言に尽きる。
逆に今のゲームはもっとすごいんだろうけど、本当に出来が良い。
まぁ、設定に追われてチュートリアルを終わったくらいしかやってないんだけど、それでもPS3より断然綺麗。
360は・・・ちょっとかわいそうに見える。。。
そんくらい綺麗。
と言うわけで、いくつかスクリーンショットでも。

始まり始まり~。


巨大なネズミの死骸。。。


ユリエル・セプティム皇帝


曲者共と交戦中のブレイズ


先へと急ぐご一行


曲者共の屍


甲冑を着た曲者がブレイズに倒され、甲冑の魔法が解ける瞬間


志村!後ろ!


志村・・もとい、皇帝・・・。


シャバは遠いのぅ。


やっとシャバへ。月(?)が異常にでかい。


さて、冒険しますか。

Post to Twitter

関連する投稿

, , ,

2 Comments

c++でのファイル読み込みテスト

ゲームプログラマになる前に覚えておきたい技術」を読んでいて、C++のファイル読み込みをやっていた。
Cの時でさえ、そんなにファイルいじったりしていなかったので、ちょっと自分でも書いてみる。
まぁ、写経的なコードになっちゃうんだけれども。

main.cpp

#include <iostream>

using namespace std;

bool readFile( char** buff, int* size, const char* filename );

int main()
{
	char *fBuff = 0;
	int fSize = 0;
	if ( readFile( &fBuff, &fSize, "test_dat.txt" ) ) {
		cout.write( fBuff, fSize );
	}

	delete[] fBuff;
	return 0;
}

fileRead.cpp

#include <fstream>

using namespace std;

bool readFile( char** buff, int* size, const char* filename )
{
	// 初期化
	*buff = 0;
	*size = 0;

	// ファイルストリームをインスタンス化しつつストリームオープン
	ifstream ifs( filename, ios::binary );

	// 失敗
	if ( !ifs ) { return false; }

	ifs.seekg( 0, ifstream::end ); // ファイルストリームを最後まで移動

	// 現在の読み込み位置(詰まるところサイズ)を取得
	// tellg()はpos_type型を返すので、実体はintでも一応キャスト
	*size = static_cast< int >( ifs.tellg() );

	ifs.seekg( 0, ifstream::beg );	// ファイルストリームを先頭へ

	// メモリ確保
	*buff = new char [ *size ];

	// ファイルの内容をメモリに読み込む
	ifs.read( *buff, *size );

	return true;
}

test_dat.txt

Hello.
And say goodbye.

で、結果。

% g++ -o test main.cpp fileRead.cpp
% ./test
Hello.
And say goodbye.

ちなみに、

delete[] *fBuff;

とても、

delete[] &fBuff;

としても怒られた。
ダブルポインタは大本の変数名だけ指定すれば良いんですかい?
メモリリークとかしないのか?
この前紹介した「OpenGLで作るiPhone SDKゲームプログラミング」では

ParticleSystem::~ParticleSystem()
{
	int i;

	for (i = 0; i < this->amount; ++i) {
		delete this->particle[i];
	}
	delete this->particle;
}

なんてコードがあったから、面倒くさいけど個別に解放しないとリークしちゃうのかと思った。
そうか、その配列内でさらにnewしているから個別に解放しているのか。
そうじゃない場合はそのまま解放して良い、と。
ポインタをもっとよく勉強せねば。。。

そんだけ。

Post to Twitter

関連する投稿

, , ,

No Comments

Bad Behavior has blocked 129 access attempts in the last 7 days.