Archive for category Computer

Zend Frameworkのインストール

ちと所用でZend Frameworkを使わなくてはいけないっぽいので当サーバへインスコすることに。
FreeBSDなのでportsからサクッと入れてしまいまひょ。

% portinstall www/zend-framework

or

% cd /usr/ports/www/zend-framework
% make install clean

とか。
コンパイル中に2回ほどオプション選択させられるけど、自分の使っているDBとかと相談して決めてみてはいかがだろうか。

で、最終的に

Now you need to adjust PHP's include_path to contain
`/usr/local/share/ZendFramework/library'
For example, insert:
include_path = ".:/usr/local/share/ZendFramework/library"
into `/usr/local/etc/php.ini'.
Zend Framework includes the Zend_Tool class and wrapper script
for automating many common framework-related tasks. To use the
zf wrapper script, set the following environment variable:
Bourne shell:
export ZEND_TOOL_INCLUDE_PATH_PREPEND=\
/usr/local/share/ZendFramework/library
C-shell:
setenv ZEND_TOOL_INCLUDE_PATH_PREPEND \
/usr/local/share/ZendFramework/library
Documentation for the Zend_Tool class is found at:
http://framework.zend.com/manual/en/zend.tool.framework.html
For more general information about the Zend Framework, please
visit: http://framework.zend.com/

こんなメッセージが出る。
Zend_Tool classの事はよ~知らんから放置。
php.iniにあるinclude_pathを指示通り書き直す。

% vim /usr/local/etc/php.ini
(略)
include_path = ".:/usr/local/share/ZendFramework/library"

そんでもって、apache再起動。

% apachectl restart

せっかく140MB強までダイエットに成功したhttpdが一気に190MB手前にまでふくれあがってしまった。。。
サーバ管理技術を身につけたい。。
サーバを強化および低消費電力化したい。。。

で、お決まりのテストコード。

<?php
require 'Zend/Version.php';
echo Zend_Version::VERSION;

Zend Frameworkコード規約によりPHPのみのファイルでは終了タグ?>は書かない。
結果は下記ページの通り。
http://yuxx.net/~yuxx/zend_ver.php

とりあえずインストール完了なり:-)

Zend Framework 徹底マスター

著者/訳者:藤野 真吾

出版社:ソーテック社( 2009-04-11 )

定価:

Amazon価格:¥ 26,137

単行本 ( 592 ページ )

ISBN-10 : 488166669X

ISBN-13 : 9784881666692


Post to Twitter

, , , ,

No Comments

JailbreakMeでiPhone4(iOS 4.0.1)を今さらJailbreak

噂のPDF関連のexploitを突いたJailbreak、JailbreakMeを試してみました。
やるんだったらご自由にと言うか、自己責任です。
アポーのサポート切れます。
なお、iOSを最新の4.0.2にアップデートしている場合、JailbreakMeは元より、Jailbreak自体も今のところ出来ないので注意。
それを踏まえて行ってみよ~♪


とりあえず、iPhoneのSafariでhttp://www.jailbreakme.comを開く。

スライダーをスライドさせると「草の根App Store」ことCydiaなどのダウンロードが開始される。

うちの回線だとダウンロードからインストールまで2~3分かかった。

で、完了。
このページは閉じて良し。
どっかにCydiaの茶色いアイコンがあるはずなので、それをタップ。

立ち上げると「ユーザ」、「ハッカー」、「ディヴェロッパ」の3タイプが選べる。
開発する気はないけど、コマンドラインは使うから「ハッカー」にしておいた。

アップグレードを催促してくるから、上の2つのうちどっちかを選ぶ。
俺は面倒くさがりだから「Complete Upgrade」を選んだり。

で、再起動がかかったかかからないか忘れたけど、再起動やらホーム画面に戻ったりしてたらもう一度立ち上げる。

ここのECIDと言うのが重要らしいから、とりあえずメモしておく。
スクリーンショット取っても良いかと。
(ちなみに画像中のECIDは加工してますのであしからず。)

とりあえず検索で例のSafariでPDFを勝手に開いて勝手にコードを実行されるのを防ぐために、PDFを開く際の確認画面を挟むパッチを入れる。
検索欄で「PDF」と打てばすぐ出るはず。

一番上のステータスバーをすりすりすると出てくる便利設定ソフト「SBSettings」もお忘れ無く。

危険は承知で「OpenSSH」も導入。
入れたらすぐにステータスバーをすりすりしてOffにすること。

すりすり出来なかったときのために、SSHのオンオフだけをコントロールできるアイコンも追加。

ホーム画面下にあるDockを5列にするパッチ。
これはやめられまへん。。

バッテリー残量表示をRed Bullの缶の潰れ具合で確認できるテーマも導入。
(何故標準で替えられない!)

出先でiPhoneを踏み台にしてネットしたい場合は・・・。
SoftBankではライセンス違反なので、自己責任で。
(日本通信のb-mobileならOKらしいけど。。)

とまぁ、こんな感じになる。

Post to Twitter

, , , ,

No Comments

tarコマンドのメモ

ターミナルを使う時はメチャクチャ使うんだけど、使わない時は全く使わない昨今。
なんと、tarコマンドまで忘れてしまう始末。
しかも、欲しい形での情報が見つからないことしばしば。
なので、自分向けメモを残すことに。
自分向けだから、よく使うオプションのみ:P

オプション オプション内容
c アーカイブを作成
x アーカイブを展開
j bzip2で圧縮(cモード – 圧縮モード – のみ)
z gunzipで圧縮(cモード – 圧縮モード – のみ)
v 冗長(詳細)表示出力
f ファイルの指定

例)
bunzip圧縮

% tar cjvf filename.tar.bz2 /path/to/dir_name

gunzip圧縮

% tar czvf filename.tar.gz /path/to/dir_name

※拡張子は自分で付けるっぽい。

bunzip解凍

% tar xjvf filename.tar.bz2

gunzip解凍

% tar xzvf filename.tar.gz

※FreeBSDでは書庫を自動判断してくれるっぽい。(恐らくLinuxでも。)

詳しくは

% man tar

まで。

そんだけ。

Post to Twitter

, ,

No Comments

FreeBSD 8.0にpTeXを入れてWP-LaTeXで使う

以前に「Bezier曲線の式でLaTeXのテスト」と言う記事を書いた。
で、この時どうしてもFreeBSD 7.1にTeXが入らなくて、WP-LaTeXと言うWordPressプラグインを外部サーバのTeXで動かしていた。
そして最近、FreeBSDを8.0へバージョンアップしたこともあって、いろいろアプリをバージョンアップしていたわけ。
その時もいろいろPorts自体のアップグレードが上手く行ってないっぽいことや、Portsで使っているのか知らないけど、Rubyが警告を吐いたりして、TeXどころじゃなかった。
さらにこれまた最近WordPressを3.0にアップグレードしたらユーザやらサイト情報が保存されないトラブルに直面して、ブログ自体を再構築しようかと迷っていた。
そして注意力散漫な俺はメールサーバ機能が正しく動いていないのをいい加減直したいと思いつつ、数学の勉強をしようとpTeXを入れたくなってしまった。

とまぁ、個人的な動機はさておき、ついに導入できたのでちょっとした備忘録でも。
と言っても、「FreeBSD における TeX の導入」をなぞっただけと言う噂も・・・。
まず、ja-ptex-tetexをインストールする。

% sudo portinstall ja-ptex-tetex

次はja-xdvik-tetexをインストール。
(ひょっとしたらWP-LaTeXにはいらないのかもしれない。)

% cd /usr/ports/japanese/xdvik
% make install

次はja-dvipsk-tetexをインストール。

% cd /usr/ports/japanese/dvipsk
% make install

もしインストール中に古いパッケージとの衝突があるようなら、それをアンインストール。
例えばうちの環境ではxdvik導入中にja-ipa-ttfonts-1.0.20060520.p1_2,2とのコンフリクトがあったから

% pkg_delete ja-ipa-ttfonts-1.0.20060520.p1_2,2

してxdvikを入れた。
恐らくそれで新しいバージョンが入ったはず。

さらにdvipskではdvipsk-tetex-5.95a_5と衝突。

% pkg_delete dvipsk-tetex-5.95a_5

としたらteTeX-3.0_4の依存関係を指摘される。。。
なので、

% pkg_deinstall teTeX-3.0_4

としてteTeX-3.0_4をデインストール後、

% pkg_delete dvipsk-tetex-5.95a_5

として削除してxdvikをインストール。
これでOKだった。

WP-LaTeXのオプションをWordPressの設定画面から選択。

で、latexとdvipngの場所をwhich調べる。

% which latex
/usr/local/bin/latex
% which dvipng
/usr/local/bin/dvipng

ちなみに、FreeBSDではwhereとwhereisでも調べられる。

% where latex
/usr/local/bin/latex
% where dvipng
/usr/local/bin/dvipng
% whereis latex
latex: /usr/local/bin/latex /usr/local/man/man1/latex.1.gz /usr/ports/print/latex
% whereis dvipng
dvipng: /usr/local/bin/dvipng /usr/local/man/man1/dvipng.1.gz /usr/ports/japanese/dvipsk/work/tetex-src-3.0/texk/dvipng

サーバのパスをこうして簡単に書いてしまうのもアレかもしれないけど、とりあえず載せてしまうw

上記の様に、パスを設定して保存した後、数式が表示されればOK。

例によってテスト。
E=mc^2

そんだけ。

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 &quot;C:\Program Files\Quake III Arena\&quot; +set r_mode &quot;4&quot;

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

seta r_fullscreen &quot;1&quot;

seta r_fullscreen &quot;0&quot;

として抑えた。

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

これが出なくてオープニングムービーが始まって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 &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdarg.h&gt;
#include &quot;debug.h&quot;
#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( &quot;dprintf:malloc error.\n&quot; );
return _DPRINTF_MALLOC_ERR_;
}
if ( format == NULL ) {
OutputDebugStringA( &quot;dprintf:format argument is null.\n&quot; );
return _DPRINTF_ARG_ERR_;
}
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
// vsnprintfにてバッファ終端に'&#92;&#48;'が書き込まれない
// 時があったので、strlenでも長さチェックをかける。
// あるいは、この時点でスタックを破壊している可能性もある。
if ( (int) strlen( debugMsgBuffer ) &gt; msgLen ) msgLen = -2;
// メモリが足りないときの処理
while ( msgLen &lt; 0 ) {
maxBuffSize += _DEBUG_BUFF_BASE_SIZE_;
tmpMsgBuffer = (char *) realloc( debugMsgBuffer, maxBuffSize );
if ( tmpMsgBuffer == NULL ) {
free( debugMsgBuffer );
OutputDebugStringA( &quot;dprintf:realloc error.\n&quot; );
return _DPRINTF_REALLOC_ERR_;
}
debugMsgBuffer = tmpMsgBuffer;
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
// vsnprintfの'&#92;&#48;'書き忘れ問題をここでも対処。
if ( (int) strlen( debugMsgBuffer ) &gt; msgLen ) msgLen = -2;
}
OutputDebugString( debugMsgBuffer );
free( debugMsgBuffer );
return msgLen;
}

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

if ( (int) strlen( debugMsgBuffer ) &gt; msgLen ) msgLen = -2;

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

vsnprintfでおかしくなる。

// debug.cpp
#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdarg.h&gt;
#include &quot;debug.h&quot;
#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, &quot;C&quot; );
va_start( argPtr, format );
debugMsgBuffer = (char *) malloc( maxBuffSize );
if ( debugMsgBuffer == NULL ) {
OutputDebugStringA( &quot;dprintf:malloc error.\n&quot; );
return _DPRINTF_MALLOC_ERR_;
}
if ( format == NULL ) {
OutputDebugStringA( &quot;dprintf:format argument is null.\n&quot; );
return _DPRINTF_ARG_ERR_;
}
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
// vsnprintfにてバッファ終端に'&#92;&#48;'が書き込まれない
// 時があったので、strlenでも長さチェックをかける。
// あるいは、この時点でスタックを破壊している可能性もある。
// if ( strlen( debugMsgBuffer ) &gt; msgLen ) msgLen = -2; // ここをコメントアウト
// メモリが足りないときの処理
while ( msgLen &lt; 0 ) {
{ // debug
testLen = sprintf( test, &quot;maxBuffSize appended from \&quot;%d\&quot; to&quot;, maxBuffSize );
maxBuffSize += _DEBUG_BUFF_BASE_SIZE_;
sprintf( &amp;test[testLen], &quot;\&quot;%d\&quot;.\n&quot;, maxBuffSize );
OutputDebugStringA( test );
} // debug end
tmpMsgBuffer = (char *) realloc( debugMsgBuffer, maxBuffSize );
if ( tmpMsgBuffer == NULL ) {
free( debugMsgBuffer );
OutputDebugStringA( &quot;dprintf:realloc error.\n&quot; );
return _DPRINTF_REALLOC_ERR_;
}
debugMsgBuffer = tmpMsgBuffer;
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
{ // debug
sprintf( test, &quot;maxBufferSize = \&quot;%d\&quot;\n msgLen = \&quot;%d\&quot;\n  strlen( debugMsgBuffer ) = \&quot;%d\&quot;\n&quot;, maxBuffSize, msgLen, strlen( debugMsgBuffer ) );
OutputDebugStringA( test );
} // debug end
// vsnprintfの'&#92;&#48;'書き忘れ問題をここでも対処。
// if ( strlen( debugMsgBuffer ) &gt; msgLen ) msgLen = -2; // ここをコメントアウト
}
OutputDebugString( debugMsgBuffer );
free( debugMsgBuffer );
return msgLen;
}

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

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

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

glnWidth =  1432	glnHeight =   815

を期待したところ、

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

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

お粗末。

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 &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdarg.h&gt;
#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( &quot;dprintf error.&quot; );
return false;
}
OutputDebugStringA( debugOutBuff );
return true;
}

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

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

そんだけ。

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

Microsoft Visual Studio 2010 Professional アカデミック

Microsoft Visual Studio 2010 Professional アカデミック

定価:¥ 13,824

カテゴリ:DVD-ROM

発売日:2010-06-18



プログラミングWindows第5版〈上〉Win32 APIを扱う開発者のための決定版! (Microsoft Programming Series)

著者/訳者:チャールズ ペゾルド

出版社:アスキー( 2000-10 )

定価:

単行本 ( 790 ページ )

ISBN-10 : 4756136001

ISBN-13 : 9784756136008



プログラミングWindows第5版〈下〉Win32 APIを扱う開発者のための決定版! (Microsoft Programming Series)

著者/訳者:チャールズ ペゾルド

出版社:アスキー( 2000-10 )

定価:

Amazon価格:¥ 34,744

単行本 ( 739 ページ )

ISBN-10 : 475613601X

ISBN-13 : 9784756136015


Post to Twitter

, , , , ,

No Comments

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

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

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

#include &lt;stdio.h&gt;
int main()
{
int i;
char s[] = &quot;abcdefghij&quot;;
for ( i = 0; i &lt; sizeof( s ) - 1; ++i ) {
printf( &quot;%d:%c\n&quot;, 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( &quot;%d:%c\n&quot;, i, *( i + s ) );

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

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

// alignment_check.c
#include &lt;stdio.h&gt;
typedef struct {
char ch;
double dn;
short sn;
int nu;
} MyStruct;
int main()
{
MyStruct hoge;
unsigned long gap1, gap2, gap3;
printf( &quot;sizeof char\t%lu\n&quot;, sizeof( char ) );
printf( &quot;sizeof double\t%lu\n&quot;, sizeof( double ) );
printf( &quot;sizeof short\t%lu\n&quot;, sizeof( short ) );
printf( &quot;sizeof int\t%lu\n\n&quot;, sizeof( int ) );
printf( &quot;sizeof MyStruct\t%lu\n\n&quot;, sizeof( MyStruct ) );
printf( &quot;\t&amp;hoge's hexadecimal memory address.\n&quot; );
printf( &quot;\tname\t\ttype\t\taddress\t\tsize\n&quot; );
printf( &quot;\t&amp;hoge\t\tMyStruct\t%p\t%4lu\n&quot;, &amp;hoge, sizeof( hoge ) );
printf( &quot;\t&amp;hoge.ch\tchar\t\t%p\t%4lu\n&quot;, &amp;hoge.ch, sizeof( hoge.ch ) );
gap1 = (unsigned long)&amp;hoge.dn -
( (unsigned long)&amp;hoge.ch + sizeof( hoge.ch ) );
printf( &quot;gap1:%lu\n&quot;, gap1 );
printf( &quot;\t&amp;hoge.dn\tdouble\t\t%p\t%4lu\n&quot;, &amp;hoge.dn, sizeof( hoge.dn ) );
gap2 = (unsigned long)&amp;hoge.sn -
( (unsigned long)&amp;hoge.dn + sizeof( hoge.dn ) );
printf( &quot;gap2:%lu\n&quot;, gap2 );
printf( &quot;\t&amp;hoge.sn\tshort\t\t%p\t%4lu\n&quot;, &amp;hoge.sn, sizeof( hoge.sn ) );
gap3 = (unsigned long)&amp;hoge.nu -
( (unsigned long)&amp;hoge.sn + sizeof( hoge.sn ) );
printf( &quot;gap3:%lu\n&quot;, gap3 );
printf( &quot;\t&amp;hoge.nu\tint\t\t%p\t%4lu\n\n&quot;, &amp;hoge.nu, sizeof( hoge.nu ) );
printf( &quot;char + gap1 + double + gap2 + short + gap3 + int = %lu\n\n&quot;,
sizeof( char ) + gap1 +
sizeof( double ) + gap2 +
sizeof( short ) + gap3 +
sizeof( int ) );
printf( &quot;&amp;hoge's decimal memory address (with alighnment gap size).\n&quot; );
printf( &quot;\tname\t\ttype\t\taddress\t\tsize\n&quot; );
printf( &quot;\t&amp;hoge\t\tMyStruct\t%ll\t%4lu\n&quot;, &amp;hoge, sizeof( hoge ) );
printf( &quot;\t&amp;hoge.ch\tchar\t\t%lu\t%4lu\n&quot;, &amp;hoge.ch, sizeof( hoge.ch ) );
printf( &quot;gap1:%lu\n&quot;, gap1 );
printf( &quot;\t&amp;hoge.dn\tdouble\t\t%lu\t%4lu\n&quot;, &amp;hoge.dn, sizeof( hoge.dn ) );
printf( &quot;gap2:%lu\n&quot;, gap2 );
printf( &quot;\t&amp;hoge.sn\tshort\t\t%lu\t%4lu\n&quot;, &amp;hoge.sn, sizeof( hoge.sn ) );
printf( &quot;gap3:%lu\n&quot;, gap3 );
printf( &quot;\t&amp;hoge.nu\tint\t\t%lu\t%4lu\n&quot;, &amp;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
&amp;hoge's hexadecimal memory address.
name            type            address         size
&amp;hoge           MyStruct        0x7fff5fbfef10    24
&amp;hoge.ch        char            0x7fff5fbfef10     1
gap1:7
&amp;hoge.dn        double          0x7fff5fbfef18     8
gap2:0
&amp;hoge.sn        short           0x7fff5fbfef20     2
gap3:2
&amp;hoge.nu        int             0x7fff5fbfef24     4
char + gap1 + double + gap2 + short + gap3 + int = 24
&amp;hoge's decimal memory address (with alighnment gap size).
name            type            address         size
&amp;hoge           MyStruct        140734799802128   24
&amp;hoge.ch        char            140734799802128    1
gap1:7
&amp;hoge.dn        double          140734799802136    8
gap2:0
&amp;hoge.sn        short           140734799802144    2
gap3:2
&amp;hoge.nu        int             140734799802148    4

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

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

著者/訳者:前橋 和弥

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

定価:

Amazon価格:¥ 2,462

単行本 ( 323 ページ )

ISBN-10 : 4774111422

ISBN-13 : 9784774111421



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

著者/訳者:平山 尚

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

定価:

Amazon価格:¥ 4,860

単行本 ( 872 ページ )

ISBN-10 : 4798021180

ISBN-13 : 9784798021188


Post to Twitter

, , , ,

No Comments

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

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

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

// stack_overflow_test.c
#include &lt;stdio.h&gt;
void hello()
{
static int i = 0;
fprintf( stderr, &quot;stderr:\tHello xD\n&quot; );
printf( &quot;\tNo.%d Hello:P\n&quot;, i++ );
}
void func()
{
void        *buf[10];
static int  i;
printf( &quot;buf\t%p\n*buf\t%p\n&amp;i\t%p\n&amp;hello\t%p\n\n&quot;, buf, *buf, &amp;i, &amp;hello );
for ( i = 0; i &lt; 16; ++i ) {
buf[i] = hello;
printf( &quot;buf[%d]\t%p\n&quot;, i, &amp;buf[i] );
}
printf( &quot;\n\tEnd of func()\n\n&quot; );
}
int main()
{
int buf[1000];
printf( &quot;Start\n\n&quot; );
func();
printf( &quot;End\n\n&quot; );
return 0;
}

で、実行するとこう。

% gcc -o stack_overflow_test stack_overflow_test.c
% ./stack_overflow_test
Start
buf     0x7fff5fbfdf20
*buf    0x100000eee
&amp;i      0x10000108c
&amp;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 &lt;stdio.h&gt;
void hello()
{
static int i = 0;
fprintf( stderr, &quot;stderr:\tHello xD\n&quot; );
printf( &quot;\tNo.%d Hello:P\n&quot;, i++ );
}
void func()
{
void        *buf[10];
static int  i;
printf( &quot;buf\t%p\n*buf\t%p\n&amp;i\t%p\n&amp;hello\t%p\n\n&quot;, buf, *buf, &amp;i, &amp;hello );
hello();
for ( i = 0; i &lt; 16; ++i ) {
buf[i] = hello;
printf( &quot;buf[%d]\t%p\n&quot;, i, &amp;buf[i] );
}
printf( &quot;\n\tEnd of func()\n\n&quot; );
}
int main()
{
int buf[1000];
printf( &quot;Start\n\n&quot; );
func();
printf( &quot;End\n\n&quot; );
return 0;
}

するとこうなる。

% gcc -o stack_overflow_test stack_overflow_test.c
Start
buf     0x7fff5fbfdf20
*buf    0x100000eee
&amp;i      0x10000108c
&amp;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( &quot;buf\t%p\n*buf\t%p\n&amp;i\t%p\n&amp;hello\t%p\n\n&quot;, buf, *buf, &amp;i, &amp;hello );
hello();
for ( i = 0; i &lt; 15; ++i ) {
buf[i] = hello;
printf( &quot;buf[%d]\t%p\n&quot;, i, &amp;buf[i] );
}
printf( &quot;\n\tEnd of func()\n\n&quot; );
}

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

Start
&amp;func   0x100000d3f
buf     0x7fff5fbfeea0
*buf    0xffffffffffffffff
&amp;i      0x10000108c
&amp;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
&amp;func   0x100000d3f
buf     0x7fff5fbfeeb0
*buf    0x7365745f776f6c66
&amp;i      0x10000108c
&amp;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-01 )

定価:

Amazon価格:¥ 2,462

単行本 ( 323 ページ )

ISBN-10 : 4774111422

ISBN-13 : 9784774111421


Post to Twitter

, , , ,

No Comments

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

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

main.cpp

#include &lt;iostream&gt;
using namespace std;
bool readFile( char** buff, int* size, const char* filename );
int main()
{
char *fBuff = 0;
int fSize = 0;
if ( readFile( &amp;fBuff, &amp;fSize, &quot;test_dat.txt&quot; ) ) {
cout.write( fBuff, fSize );
}
delete[] fBuff;
return 0;
}

fileRead.cpp

#include &lt;fstream&gt;
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&lt; int &gt;( 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[] &amp;fBuff;

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

ParticleSystem::~ParticleSystem()
{
int i;
for (i = 0; i &lt; this-&gt;amount; ++i) {
delete this-&gt;particle[i];
}
delete this-&gt;particle;
}

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

そんだけ。

Post to Twitter

, , ,

No Comments