Tag Archives: C言語

各言語のtrue/false

これは興味深いです。C言語は単純なので分かりやすいですが、PHPでは微妙に独自ルールがあるなぁ~と思っていたのでこういう表があるとわかりやすいですね。この結果から言えることは「真偽の判定式は面倒でも明示的にtrue/falseに収束するように書くように」ってところかな。今までもPHP等でif($obj)みたいなコードがバグの原因となっていたケースをよく発見していたので、変数が定義済かどうか真偽の二値に収束しているかしっかり書くように勧めたいと思います。

特にPHPは変数宣言を用意してない癖に値の型はC言語以上に細かいので条件に利用するときは面倒なこともあります。0(数値)とfalse(偽)とNULLとEMPTY(空文字列)とUndefined(未定義)のどれがやってくるかわからない場合の判別とか。

各言語におけるtrue/falseまとめ – 床のトルストイ、ゲイとするとのこと
http://d.hatena.ne.jp/mirakui/20090604/truefalse

ApacheModuleの作り方

C言語のCGIは速いと思っていましたが実は遅かったんですね。Servletみたいにプログラムがメモリに常駐されていればディスクアクセスが発生するCGIに勝ち目は無いのか・・・でもFastCGI組み込んだらどうなんだろ?

以下の記事はCGIをC言語で作るというより、Apacheモジュールの作り方に重点を置いています。Webシステムのモジュールをバイナリ形式で配布する際にとても参考になりそうです。

ApacheModuleでWebアプリケーションをつくろう:CodeZine
http://codezine.jp/a/article/aid/2502.aspx

メルマガのソース配布

メールマガジン御購読ありがとうございました。そしてお疲れさまでした。今年のGWシリーズのサンプルソースを配布します。

コンフィグファイルの読み込み(C++とSTL利用)
2007050601-1

これにコンフィグ新規作成・書き込み用クラスなんて作るととりあえずまともかな。カレントディレクトリの認識は特にやってないのでそこが甘いかもしれません。実際に使用するときはその辺の応用も考慮して修正してくださいです。

半年ぶりにメルマガ発行

メルマガを久しく発行してなくて強制退場されかけていました。本来ならMMO開発の進捗にあわせてTips感覚で発行続けようとしていましたが肝心のプロジェクトに手を付けられず周辺の作業ばかりでネタの作成ができていませんでした。今回は期限もあったのでかなり意識して作成しました。

本日発行したメルマガで書いたプログラムはここからダウンロードできます。

2007042901-1

Core吐かせてみよう

今日はトンデモな実験。というかここ数年Core吐かせてないのでデバッグ用にわざと吐かせてみた。

#include
int main(){
int i=0;int j=1;int k=0;
printf(“i=%d,j=%dn”,i,j);
k=j/i;
printf(“k=%dn”,k);
return 0;
}

コンパイル
> gcc -o fault fault.c

実行
> ./fault
i=0,j=1
Floating exception (core dumped)

まぁ酷いプログラムです。
実行すればたちまち0除算が原因でcoreを吐きます。
今までWindowsも含めてコアダンプを利用した解析なぞやったこと無かったので、バイナリエディタで開く…。全く読めない。そこで調べていたらgdbコマンドを使えば直ぐにわかるという。これがあれば解析のためにガリガリファイルにログを書き出さなくていいかもです。

まずは試しに実行。(実行ファイル名はfaultでコアダンプはfault.coreです)

> gdb fault fault.core
#0 0x0804854e in main ()

main関数でダウンしたことがわかります。

今度はデバッグモードでコンパイル(特に再実行してコアを更新する必要はなさそうです)
> gcc -g -o fault fault.c
> gdb fault fault.core
#0 0x0804854e in main () at fault.c:8
8 k=j/i;

なるほど、fault.cの8行目で停止したことがわかります。

PostgreSQLへC言語で接続する

MySQLが一段落したので今度はPostgreSQLへ接続してみます。

ソースファイルはこちら(C言語)
pg20060521-1

PostgreSQLとMySQLでは値の取り出し方法が違うみたいですね。C++でクラス化する際には共通のほ方法で利用できるように考慮したほうが良いですね。(DBI使ったほうが早いとか置いといて)

もうひとつ重大な問題がこのソースにはあります。SELECTで*を指定しておいて取り出し時に何番目というやり方で行っていること。つまりテーブルのフィールドに追加変更があった場合にプログラムが動かなくなってしまう危険があります。単にSELECTで*を使わなければ良いのですがそれでも要素名でアクセスできないのは可読性に影響します。

C++版は以上を考慮に入れてMySQL版と移植性の高いものを作ってみます。

MySQLをC言語から使う

PerlやPHPからではDBIや内蔵ライブラリ任せで良いのですが、C言語では直接MySQLのライブラリを使用します。

まずは、必要なヘッダやライブラリがどこにあるかを調べる。
# find / -name mysql.h
/usr/local/src/mysql-5.0.18/include/mysql.h
/usr/local/mysql/include/mysql/mysql.h

# find / -name libmysqlclient.so
/usr/local/src/mysql-5.0.18/libmysql/.libs/libmysqlclient.so
/usr/local/mysql/lib/mysql/libmysqlclient.so

# find / -name libmysqlclient.a
/usr/local/src/mysql-5.0.18/libmysql/.libs/libmysqlclient.a
/usr/local/mysql/lib/mysql/libmysqlclient.a

コンパイル・リンク時に-Iや-Lで指定が必要になります。
# gcc -c -I /usr/local/mysql/include/mysql/ myclient.c
# gcc -o myclient -L /usr/local/mysql/lib/mysql/ -l mysqlclient

一気にやるならこっち
# gcc -o myclient
-I /usr/local/mysql/include/mysql/
-L /usr/local/mysql/lib/mysql/
-l mysqlclient
myclient.c

実際のプログラムに関してはメルマガで紹介しますが、Linuxの場合出来上がったプログラムを使用する際に/usr/local/mysql/lib/mysql/をldconfigで登録しないとだめだったので動的リンクだったかも。
FreeBSDにも同じコマンドがあるのでメルマガ発行前にもう一度検証してみます。

デバッグ完了

UNIX版から開発しているから、次にWindowsで動かす時のデバッグに時間が掛かった。原因はFD_SETSIZE絡み。UNIXだとFD_SETSIZEのサイズは1024で以下のようにディスクリプタが振られた。

0…標準入力
1…標準出力
2…標準エラー出力
3…ソケットサーバー
4…クライアント1(telnet)
5…クライアント2(telnet)

この時点では数の少ないほうからディスクリプタが振られ1024には遠く及ばないので特に問題ではない。

これがWindowsだとコマンドプロンプトから起動した場合

1956…ソケットサーバー
1928…クライアント1(telnet)
1912…クライアント2(telnet)

直接実行ファイルをダブルクリックして起動した場合でも、

96…ソケットサーバー
124…クライアント1(telnet)
140…クライアント2(telnet)

といった感じで肝心のFD_SETSIZEは64で定義されている為、そのままでは役に立たないどころかオーバーフローを起こしてサーバーが落ちてしまっていた。結局Windowsの場合はFD_SETSIZEを2048に再定義するという方法で逃げた。正直ココまでばらついているとループ回数が増える分不利な気がする。

この時点でチョットの変更でFLASHクライアント用になれるチャットサーバーができました。サーバー自身はデータの中身について全く検査はしてないのとバッファは固定値なので大量にデータを送ると最大値以降の文字は削除されてしまうくらいです。

ソースのダウンロードはこちら(EUC)
socket_server_select

Win32とUNIXで条件分け

只今、メルマガ向けのSocketプログラミングをしているところですが(UNIX版は終了)、同じソースで条件分けする際にヘッダーファイルで定義しないとダメのかなと思っていたら、コンパイラ自身である程度定義が入っているとネット上の情報で発見。実際はコンパイル時に必ず読み込まれるヘッダー辺りにも書いていると思いますが、その内容の今回使用する部分を抜粋。

GCC(UNIX系)の場合
#define __GNUC__

Windowsの場合
#define _WIN32

つまり、ヘッダーファイルの名前が違うとか、ライブラリ関数の差異を埋めるためには、

#ifdef __GNUC__
// ここにUNIX版の処理を記述
#endif
#ifdef
// ここにWindows版の処理を記述
#endif

このようにすればOK

参考:Hey! Java Programming! –移植性–http://www.mars.dti.ne.jp/~torao/program/general/portability.html