Archive for 12月, 2009
Visual Studio 2008 Express Editionを使い始める、の巻
ちょっとCとC++の勉強もあったまってきたので、「猫でもできるプログラミング」を参考にしながらWindows SDKプログラミングもちょっくらいじりだそうかと思っている昨今。
さっそくイントロダクションでつまったので、備忘録を載せておくことに。
写経すること数分、正直言ってビルド失敗。
で、チキン野郎なので、そのままコピペ・・・したら(エンコーディングの問題からか、)1行になったので、それを分解・・・。
するとどうでしょう。
うごかねぇ~~。。
そのエラーを探ること数分、見つけましたよ、原因を。
そもそも、このページのオーナーさんである粂井さんが一連の記事を書き始めたときのVCのバージョンが4.0だったことが事の発端なんだとか。
というわけで、どこを直せばいいかを書いておこうかなぁ、と。
まず、コンパイラのエラーを見る。
error C2440: '=' : 'HGDIOBJ' から 'HBRUSH' に変換できません。
'void*' から非 'void' 型への変換には明示的なキャストが必要です。
error C2440: '=' : 'char [25]' から 'LPCWSTR' に変換できません。
指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。
error C2664: 'CreateWindowExW' : 2 番目の引数を 'char [25]' から 'LPCWSTR' に変換できません。(新しい機能 ; ヘルプを参照)
指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。
最初に、本来HBRUSH型を要求するhbrBackgroundにGetStockObject(WHITE_BRUSH)を入れていることからエラーとなったご様子。
HGDIOBにキャストしてみる。
2番目はszClassNameがchar型なのに対して、LPCWSTR型を要求する場所を引数として入れていることが問題のご様子。
LPCWSTRにキャストしてみる。
(3箇所)
で、該当箇所はこの辺り。
WNDCLASS myProg;
if (!hPreInst) {
myProg.style = CS_HREDRAW | CS_VREDRAW;
myProg.lpfnWndProc = WndProc;
myProg.cbClsExtra = 0;
myProg.cbWndExtra = 0;
myProg.hInstance = hInstance;
myProg.hIcon = NULL;
myProg.hCursor = LoadCursor(NULL, IDC_ARROW);
// VC 6.0以降は型のチェックが徐々に厳しくなっている。
// 本来HBRUSH型を要求するhbrBackgroundにGetStockObject(WHITE_BRUSH)を入れたところ、
// エラーとなるのでHGDIOBにキャストしている。
//myProg.hbrBackground = GetStockObject(WHITE_BRUSH);
myProg.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
myProg.lpszMenuName = NULL;
// myProg.lpszClassName = szClassNme;
myProg.lpszClassName = (LPCWSTR) szClassNme;
if (!RegisterClass(&myProg)) return FALSE;
}
hWnd = CreateWindow(
//szClassNme,
//"俺にもできる?Windowsプログラミング",
(LPCWSTR) szClassNme,
(LPCWSTR) "俺にもできる?Windowsプログラミング",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
で、これを実行すると・・・。

タイトル、化けちゃってるね・・・。
どうやら、そもそもの修正方法が違うらしい。
粂井さんのサンプルはどうやらSJIS前提らしく、関数もSJIS前提の関数とかっぽい??
現状のプロジェクトファイルはUnicodeで設定されていて、それを直したりすれば行けるっぽい。
とりあえず、文字エンコーディングを直す。
(Alt-F7でプロジェクトのプロパティ)
プロジェクトのプロパティで「構成」が「Unicode文字セットを使用する」とか書いてあると思うんだけど、

「マルチバイト文字セットを使用する」とする。

恐らくこれでSJISになる。
で、今度は別のエラーが。
error C2440: '=' : 'LPCWSTR' から 'LPCSTR' に変換できません。
指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。
error C2664: 'CreateWindowExA' : 2 番目の引数を 'LPCWSTR' から 'LPCSTR' に変換できません。(新しい機能 ; ヘルプを参照)
指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。
なんだとか。
・・・LPCWSTR型にしなくてよかった、と。。。
さっきの箇所は、これでいいらしい・・・。
WNDCLASS myProg;
if (!hPreInst) {
myProg.style = CS_HREDRAW | CS_VREDRAW;
myProg.lpfnWndProc = WndProc;
myProg.cbClsExtra = 0;
myProg.cbWndExtra = 0;
myProg.hInstance = hInstance;
myProg.hIcon = NULL;
myProg.hCursor = LoadCursor(NULL, IDC_ARROW);
// VC 6.0以降は型のチェックが徐々に厳しくなっている。
// 本来HBRUSH型を要求するhbrBackgroundにGetStockObject(WHITE_BRUSH)を入れたところ、
// エラーとなるのでHGDIOBにキャストしている。
//myProg.hbrBackground = GetStockObject(WHITE_BRUSH);
myProg.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
myProg.lpszMenuName = NULL;
myProg.lpszClassName = szClassNme;
if (!RegisterClass(&myProg)) return FALSE;
}
hWnd = CreateWindow(
szClassNme,
"俺にもできる?Windowsプログラミング",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
お粗末さまでした。
psptoolchainをSnow LeopardなMacBook Airに入れようとして失敗中
世の中にはPSPをクラックして自作ソフトを使おうと言う人たちがいる。
で、今Cを勉強中だから、それに勢いを付けるために、その非公式開発環境であるところのpsptoolchainをMacで揃えようかと思った次第。
でもね、世の中そんなに甘くないんだよねぇ〜、と言うお話。
実はここ数月、Snow LeopardなMacBook Airにそのpsptoolchainをインストールしようと四苦八苦してたんだよね。
でも今のところダメ。
と言うわけで、自分がどこまで調べて、何をやって、どこまでダメなのかを備忘録として残すことに。
2010/02/11追記
よっふぃ〜さんがインストールに成功された模様なので、そちらを参照してください。
http://yoffy.dyndns.org/2010/02/pspsdk_on_mac_os_x_106.html
追記終了。。。
まずやったことは、いろいろなサイト(例えばこことか)に書いてある通り、一般的なツール類をMacPortsからインストールした。
必要なものは、
autoconf
automake
wget
Subversion
とか。
とある場所では
autoconf
automake
bison
flex
gcc
make
ncurses
paptch
subversion
texinfo
wget
なんだとか?
ただ、ここではdoxygenがあると便利とか?
まぁ、おおむねそんな感じの物が必要です、と。
と言うわけで、
McLaren% sudo port install autoconf automake wget subversion
とかやっちゃうわけです。
心配な人は
McLaren% sudo port install autoconf automake bison flex gcc make ncurses paptch subversion texinfo wget doxygen
とかね。
で、どっかにテケトーなディレクトリを作るわけです。
俺はとりあえずDownloadsに置いてみた。
McLaren% mkdir pspdev_temp Mclaren% cd pspdev_temp
お次はシェルの設定ファイルにPATHを通す。
普通のMacでは.bashrcに以下を書き込む。
export PSPDEV=/usr/local/pspdev export PATH=$PATH:$PSPDEV/bin
俺はzshなので.zshrc。
でもこの構文は同じだから同じ記述でOK。
で、PSPDEVの対象がインストール先になる。
実はこれ、どこでもいいらしく、/usr/localじゃなくてもMacPortsの/opt/localとかでもいいし、$HOMEでもぶっちゃけいいらしい。
書き換えが終ったらSubversionでダウンロード。
McLaren% svn checkout svn://svn.ps2dev.org/psp/trunk/psptoolchain
(checkoutをcoにしてもOK)
これで作業用ディレクトリにpsptoolchainが出来たはず。
そこに移動して、
McLaren% ./toolchain.sh
とするとコンパイルおよびインストールが進みますよ〜、と言うふれこみ。
するとどうでしょう。
configure: error: Building GCC requires GMP 4.1+ and MPFR 2.3.0+. Try the --with-gmp and/or --with-mpfr options to specify their locations. Copies of these libraries' source code can be found at their respective hosting sites as well as at ftp://gcc.gnu.org/pub/gcc/infrastructure/. See also http://gcc.gnu.org/install/prerequisites.html for additional info. If you obtained GMP and/or MPFR from a vendor distribution package, make sure that you have installed both the libraries and the header files. They may be located in separate packages. ../scripts/002-gcc-4.3.2-stage1.sh: Failed.
GMPかMPFR(もしくはその両方)がおかしいですよ〜、だって。
あ、ちなみに、それ以前に見つからないよ〜系のエラーは恐らくpsptoolchain/dependsのチェック処理でgmpとmpfrのチェックディレクトリが違うから。
そのファイルを開いて下記のように書き換えること。
check-gmp.sh
#!/bin/sh
# check-gmp.sh by Dan Peori (danpeori@oopo.net)
## Check for the gmp library.
# ls /usr/local/gmp-4.3.1/include/gmp.h 1> /dev/null || { echo "ERROR: Install gmp before continuing."; exit 1; }
## Custm for Mac
ls /opt/local/include/gmp.h 1> /dev/null || { echo "ERROR: Install gmp before continuing."; exit 1; }
check-mpfr.sh
#!/bin/sh
# check-mpfr.sh by Dan Peori (danpeori@oopo.net)
## Check for the mpfr library.
#ls /usr/include/mpfr.h 1> /dev/null || { echo "ERROR: Install mpfr before continuing."; exit 1; }
## Custom for Mac
ls /opt/local/include/mpfr.h 1> /dev/null || { echo "ERROR: Install mpfr before continuing."; exit 1; }
こうすれば、MacPortsにインストールされたGMPとMPFRを見るようになる。
んで、いろいろ調べた結果、MacOS X 10.6 Snow LeopardのMPFRにはバグがあります、と。。
いろいろ調べたんだけどねぇ〜。
それこそ毎日調べた。
GMPとMPFRのソースを落としてきて、独自にビルドもした。
わかったことと言えば、GMPとMPFRは数値計算用ライブラリで、GMPが無いとMPFRがインストールできない。
要は拡張ライブラリみたいな物かね?MPFRは。
そしてなぜpsptoolchainに必要なのか?
それは、PSP用のコンパイラを作るため。
UNIXでのデファクトスタンダードであるGCCなんだけど、このGCCがGMPとMPFRを必要とするんだとか。
そもそもなんでGMPとMPFRがおかしくなっているかと言えば、Snow LeopardのOS内部が64ビットにかなり舵取りを決めたから。
とは言いつつも、ラップトップだと32ビットモードで起動しているとかなんだかややこしいんですけれども。。。それどうなのよ?アップルさん。
恐らくその辺りの問題でGMPとMPFRがおかしい。
数少ない情報をたぐり寄せると、恐らくはMPFRだけがおかしい。
おまけにソースからコンパイルしてテストすると、やっぱりエラーが出る(これは両方)。
で、それらをコンパイルできない理由がコンパイラがおかしいからとか読んだから、GCCをビルドすることに。
いや、このときはまだGCCのコンパイルにGMPとMPFRが必要だとはイマイチピンと来ていなかったんだけれども。。
結局出来なくて、MacPortsの各バージョンのGCCをインスコして、/usr/bin/gccのシンボリックリンクをそれらに修正。
更にMac用GCCのコンパイルトラブルの記事を読みあさっていて見つけた記事からすると、psptoolchainのGCCはSnow Leopardではコンパイルできなくて、4.3.2以降から出来る、と。
と言うことはpsptoolchainのGCCを最新版にすれば良いのかと思って、psptoolchainのGCCに関する場所を最新版(現時点で4.4.2)に書き換えて、更に手動でDL。
Diffに書いてある箇所を何となく見つけてきて書き換えてビルとを試みるも、そもそも内部構造が結構変わっていて断念。
問題を解決したとされる4.3.4にして書き換えを試みると、ソース的にはほぼOK。
で、ようやくコンパイルしてみると。。。
なんか、意味不明なコンパイルエラー。。。。
も〜、いや。
MacPortsのmpfrがバージョンアップされていたから、何度目かの正直を実践中。
で、やっぱダメ。。<今ここ
助けてくれそうな人は
http://www.lan.st/forumdisplay.php?f=43&daysprune=-1&order=desc&sort=lastpost
http://arnold.hyperphp.com/forums/
http://forums.qj.net/developers-dungeon/162579-psptoolchain-mac-os-x.html
辺りに居そう。
もうちょっと張り込みます。
そんだけ。
インライン関数について考える
一個前の投稿ではCの仮引数付きマクロについて取り上げたけど、本題はC++のインライン関数だったり。
仮引数付きマクロでは()で正しく演算順序を指定しないと問題が起きがちですよ、と。
で、CからインクリメントしたC++ではそれを一歩上行くインライン関数と言う物があり、より関数に近い形で置換できると言う優れもの。
使い方は以下の通り。
#include <iostream>
using namespace std;
#define PI 3.141592674
inline double area_of_circle(double r)
{
return r * r * PI;
}
int main()
{
double radius;
cout << "円の半径を入力して下さい。\n";
cin >> radius;
cout << "円の面積は" << area_of_circle(radius - 1.0 + 1.0) << "です。\n";
return 0;
}
実行結果は以下の通り
McLaren% ./inline_test 円の半径を入力して下さい。 4 円の面積は50.2655です。
18行目のように、わざと計算を挟んでみた。
仮引数付きマクロならば
radius - 1.0 + (1.0 * radius) - 1.0 + (1.0 * PI)
となるところを、
(radius - 1.0 + 1.0) * (radius - 1.0 + 1.0) * PI
と言うように、パーレンで囲わなくてもコンパイラが適宜最適化してくれると言う仕組み。
型の指定をしていることからわかる通り、型もチェックしてくれます、と。
これは便利。
ただ、独習C++によると
inline指定子は、コンパイラにとってはコマンドではなく要求であることを覚えておいてください。
とのこと。
どうやらループとか書いてあるとダメなコンパイラもあるらしい。
ただ、普及しているコンパイラはOKっぽい?
そもそも自分で明示的にインライン関数にするのは好ましくないから、コンパイラが自動的にインライン化する機能を有しているので、それに任せた方が良いんだとか。
ん〜、さすが後発言語。
何から何まで便利。
で、インライン化できなかった場合は普通の関数になるらしい。
ここで疑問になるのがプロトタイプ宣言の是非なんだけど、Wikipediaによれば
インライン関数はモジュール単位に定義する必要がある(通常の関数は1つのモジュールで定義すればよい)。これにより、モジュール単位に独立したコンパイルができるようになっている。
となる。
と言うことは、モジュール単位で書くのが当然で、外部から呼び出すのは無理?もしくはナンセンス?
一応ちょっと試したんだけど、ヘッダに書いたら読める。
ただ、別ソースファイルに書いたら読めなかった。
なるほど、独立しているとはそう言うことなのか??
一応動くソースは下記の通り。
(文字列を渡すところで警告あり。でも動く。)
inline_test_main.cpp
#include <iostream>
#include "inline.h"
using namespace std;
int main()
{
double radius;
echo("円の半径を入力して下さい。");
cin >> radius;
cout << "円の面積は" << area_of_circle(radius) << "です。\n";
return 0;
}
inline.h
#include <iostream>
using namespace std;
#define PI 3.141592674
void echo(char []);
inline double area_of_circle(double r)
{
return r * r * PI;
}
inline.cpp
#include "inline.h"
void echo(char str[])
{
cout << str << endl;
}
コンパイルと実行結果は下記のとおり。
McLaren% g++ -o inline inline_test_main.cpp inline.cpp inline_test_main.cpp: In function ‘int main()’: inline_test_main.cpp:9: 警告: deprecated conversion from string constant to ‘char*’ McLaren% ./inline 円の半径を入力して下さい。 3 円の面積は28.2743です。
そんだけ。
Cの仮引数付きマクロ(マクロ関数)について考える
今ちょうどCをまじめに勉強中。
何度目かの正直・・・。
で、仮引数付きマクロ、いわゆるマクロ関数について整理しておこうかなぁ、と。
マクロ関数の基本としては、
#include <stdio.h>
#define PI 3.141592674
#define circle(r) (r) * (r) * PI
#define echo(str) printf("%s", str)
main()
{
double radius; // 半径
char str[] = "半径を入力して下さい\n";
echo(str);
scanf("%lf", &radius);
printf("面積は%.2fです。\n", circle(radius));
return 0;
}
とすると、
McLaren% ./marco 半径を入力して下さい 2.1 面積は13.85です。
となる。
何をやっているかと言えば、定数PIは3.141592674と定義。
問題はcircle(r) (r) * (r) * PI。
ソース内でcircle(radius)と呼び出すとその部分が(radius) * (radius) * PIと置換される。
文字通り置換されるらしい。
そのタイミングはコンパイル時。
で、それを連発すると関数呼び出しによるオーバーヘッドが無い分高速化はされるけど、ソースと実行ファイルは肥大化しますよ、と。
それはカーニハン&リッチーのプログラミング言語C(以下、K&R)に書いてある通り。
(p.109 第2版)
で、なぜ(radius) * (radius) * PI と回りくどい書き方をしているかと言うと、それもK&Rに書いてある。
仮引数r がもしhoge – 100 とかだと、r * r * PI だとhoge – 100 * hoge – 100 * PIとなる。
もうちょっと詳しく書くとhoge – (100 * hoge) – (100 * PI) となってしまう。
だからこう書かないと、期待した値にならないよ、と。
実はこのコードの初版ではそのことに気がつかずに書いていたから、急いで直したのはここだけの話w
そうそう、K&Rでは一言も「マクロ関数」とは書いていない。
あくまで「仮引数付きマクロ」とのこと。
まぁ、実際問題関数じゃないからそこは意見が分かれることなんだろうけど、所詮ニュアンスの違いじゃないの?と思ってしまう今日この頃。
そんだけ。
cygwinでGLUTを使う
とりあえず、setup.exeから探す。
develとか辺りにあるはずなので、それらをチェックしてインスコ。
ちなみに、一番重要と思われるのがfreeglut。
これ入れてないとダメっぽい。
あと、
http://www.xmission.com/~nate/glut.html
からWindows用のOpenGLを入手して解凍する。
その中のREADME-win32.txtに書いてあるとおり、
glut32.dll to %WinDir%\System, glut32.lib to $(MSDevDir)\..\..\VC98\lib, and glut.h to $(MSDevDir)\..\..\VC98\include\GL.
とする。
Cygwinで使う場合はglut32.dllのみを使うので、C:\Windows\system\に設置するのみでOKなはず。
で、実際gccでコンパイルするとき、cigwin上からどうしても実行できなかったので、-mno-cygwin というコンパイルオプションをつけたりする。
ファイル名はソースがglut01.c、実行ファイルはtest_opengl.exe としましょう、と。
gcc -otest_opengl.exe glut01.c -lglut32 -lglu32 -lopengl32 -mno-cygwin
ただ、残念な話、自分の環境ではこれでも動かなかった。
というのも、Cygwinのバージョンが1.7の開発版で、そのGCCがVersion 4でなおかつ-mno-cygwin はベータ版のため、未整備。。
手持ちのGCCは
$ gcc --version gcc (GCC) 4.3.4 20090804 (release) 1 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
こんな感じで、GCC3だと-mno-cygwin オプションがいけるらしいので、3を探すことに。
gccと打ってからタブキーを押して
$ gcc gcc-3.exe gcc-4.exe gcc.exe gccbug-3 gccbug-4
と出たので、
$ gcc-3 --version gcc-3 (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125) Copyright (C) 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
こいつでコンパイルしましょう、となると
$ gcc-3 -otest_opengl2.exe glut01.c -lglut -lglu32 -lopengl32 -mno-cygwin
こんな感じ。
ソースは床井さんのページ
http://www.wakayama-u.ac.jp/~tokoi/opengl/libglut.html
ここの最初のソースを拝借しました。
要するに、ただウィンドウを表示するだけ。
#include <GL/glut.h>
void display(void)
{
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
お粗末さまでした。
hostnameを変更する
FreeBSDサーバでの話。
要はこのサーバね。
メールサーバを立てようと四苦八苦してるんですよ、実は。
で、ホスト名がfreebsd.localhostというふざけた名前だから行けないのかなぁ、と。
ここは一つ、alterroots.comと改めなければと反省。
まず、ホスト名を表示するには、
% hostname freebsd.localhost
です、と。
このうちサーバ名は最初のドットまでで、
% hostname -s freebsd
となります、と。
で、メールサーバとして例えばmail.alterroots.comとする場合は
% hostname mail.alterroots.com
として、更に起動スクリプトに書かれている方も修正する。
そのファイルの場所は/etc/rc.conf。
このファイルのhostname=となっているところを修正して完了。
でもメールサーバの構築は失敗している。
理由はサーバ用に取得したプロバイダがBB.exciteで、メールアカウントを持ってないから。。
(プロバイダのメールサーバを中継しないと行けないらしい)
そんだけ。
MacOSXでのJava文字化け解消とか
移り気な俺はJavaにも興味津々。
と言うわけで、いまさらJavaの端っこをかじることに。
で、Macには標準で入っている。
と言うか、Javaのバージョンアップがあったからちょいとやってみようかと思ったんだけれども。
あと、ちょっとした縁で本を借りたので、内容はWindows用っぽいけどやっぱり無理矢理チャレンジすることにw
で、最初につまずいたのがJava自身の文字化け。
どうやらShift JISをベースに出してくれるらしく、ちょっと面倒なことに。
Javaのバージョンが知りたくて
javac --version
を打ったんだけど、
McLaren% javac --version javac: --version �͖���ȃt���O�ł��B �g����: javac <options> <source files> �g�p�\�ȃI�v�V�����̃��X�g�ɂ��ẮA-help ��g�p���܂�
こんな感じに。
恐らくこのままだとエラーメッセージまでこれw
せめて英語でエラーを受けたいところ。
(文字化けと比較すれば、英語ならまだ読めるw)
で、いろいろ探したところ、シェルの設定ファイルに下記を書き込めば良いとのこと。
恐らく多くの人はbashなので~/.bashrcを。
自分はzshなので~/.zshrcを。
alias javac="javac -J-Dfile.encoding=UTF-8" alias java="java -Dfile.encoding=UTF-8"
で、もう一度Javaコンパイラのバージョンを見てみることに。
McLaren% javac --version javac: --version は無効なフラグです。 使い方: javac <options> <source files> 使用可能なオプションのリストについては、-help を使用します
おお、日本語w
(そして–versionなんてフラグは無いw)
さすが世界企業Sun。
そして愛しのVimの原型viを開発したビル・ジョイも参加して作っただけある。
やっぱすごい。
そして便利そう。
(クソ単純な俺)
そうそう、実は自分のファイルにこれだけは書いてあった。
export JAVA_OPTIONS="-Dfile.encoding=UTF-8"
一度挑戦しようとしかけたのかね?w
とは言え、失敗していたからアレなんだけれども。
と、ここまで書いたんだけど、今CおよびC++の勉強中だから、あくまで気まぐれ。
いつ続きをやるかわかりませんので悪しからず〜。
あ、ちなみに正式なバージョン情報は
McLaren% javac -version javac 1.6.0_17
と言った感じ。
(珍しく、ハイフン1つ少なくていいのね)
そんだけ。

