雑な k|m の生態について

その 14 - 只今全力減速中につき

2002-09-11

[C/C++] なぞの・・・?

#include <stdio.h>

class A {
  A() { puts("!"); }
};

int main() {
  if (A) puts("?");
  return 0;
}

んーと・・・

何これ?

・・とりあえずコメントを

上記のコードは VC++5.0 および VC++6.0 でコンパイルが可能でした。そして実行結果は "?" のみの出力。if (A) ... は一見するとクラス A のコンストラクタが起動されるように見えますが,よく見ると違います。それにクラス A のコンストラクタは private ですしね。

gcc でも試せればよかったのですが,あいにく私のマシンにはインストールしていませんでした。HDD を交換してから,ずっとインストールしていなかったんですね。さらに残念なことに会社のマシンからは cygwin をアンインストールしていました。HDD の断片化が非常に激しく,デフラグを行うのに HDD の空きが足りなかったからです。

とりあえず現在 gcc をインストール中。実験し次第,下に追記でもしておきますわん。

謎度:454173

[ アンインストール ]
ただ削除しただけです。笑い

お約束の追記です

はい,cygwin をインストールしたので早速上のコードをコンパイルしてみました。

コンパイルできませんでした。

文法的にアレなんだから当たり前ですよね。でもなぜ VC++ ではコンパイルできたんだろう? わりと世間で言われているよりは VC++ にはバグは少ないようで,一見バグに見えるものも実は MS が故意に残したものである場合が多いようです。for(int i= ...) の問題がその一例。

きっとこの現象にも何か残したかった理由が・・・あるわけないか?

東京都中野区も住基ネット離脱っ

なんだか住基ネットから離脱するのが流行ってるらしいんですが,よりにもよって私の住んでいる区が離脱するとはねー。ただし「将来住基ネットに再接続する際に混乱が起きないように番号自体は保存しておく」とのことなので,「条件付賛成」とも言えるような冷静さを感じさせます。

というよりも「0 号免許」 ( うろ覚え ) はまだですか。理論上は「運転免許証」なんだけど実はどの車両も運転できるわけではなくて,ただの身分証として使えるとかいうアレ。むっちゃくちゃ欲しいんですけど。

[ むっちゃくちゃ欲しい ]
住民票が身分証として使えなくなった今,私にはもう健康保険証しかありません・・・

2002-09-10

なぞかな

の文字を見つけました。この文字は今日付けの読売新聞夕刊に載っていたものです。

(「む」のできそこない)

「す」によけいなモノがこびりついたというか,「む」のできそこないというか,とにかくわりと楽しい字形です。何て読むんだろう? ヒントは,「長寿上位 20 位」にランクインされた方のお名前に使われていたという事実。「嶋津〓る」さん,9 月 30 日現在で 110 歳だとか。

はい,ここであの中国にシカトされはじめたことで大評判の Google の登場。無論決してこの文字を以って検索をかけることは不可能です。入力できないしね。そうではなく,ネット上でも必ず長寿な「嶋津」さんの事が話題になっているはず。ならば彼女の名前の読み方だってちゃんと載っているはずでしょう。

検索終了。読みは「は」だそうです。そういえば「うなぎ」の「な」の字も「ふ」がアンドレ・ザ・ジャイアントに轢かれたような字形をとる場合がありますが,これって何なんでしょうね。というよりもどうして日本語文字コードに定義されてないかなあ。この調子だと Unicode にも定義されないだろうから残念です。滅多に使わないけど

疲労度:24

2002-09-09

[C/C++] ポインタのちょっとしたギャグ

#include <stdio.h>

int main() {
  int *a = 0;
  a += 1;
  printf("%x\n", a );
  return 0;
}

出力結果を見て,未だに一瞬「えっ・・」とか思ってしまうんですよね。それから上のコードはきちんとコンパイルできるのに

#include <stdio.h>

int main() {
  int *a = 1;
  return 0;
}

このコードはコンパイルが通りません ( VC++5.0,gcc )。0 以外の数値は原則 int 型 ( VC++5.0 ではコンパイル時は一応 const int 型とされているけど,当然 int 型に代入可能 ) だからですね。つまり 0 はなんだか特別扱いされてるんですが。このあたりの挙動はいつもの本「プログラミング言語 C++」にて「ポインタ周りでは NULL マクロじゃなくて 0 の方がいいっすよ」と書かれていることとも大きく関連しているんですね。

疲労度:7

2002-09-08

Simple API for XML

SAX みたいなものを作ってました。今日はそれだけです。

2002-09-07

[ODBC] エラーチェックの方法 [未確認?]

たしてこのネタを出すべきだったのかどうか・・。エラー時の処理なんですが,実は確証がないんですよね。MS のサイトでもきちんとそれっぽいドキュメントは存在しますんで,いいや,このまま書いちゃえ。

処理中にエラーが起きた場合,当然その状況を示す詳細な情報が得られるに越したことはありません。しかし各関数の戻り値は単純に「成功/失敗」を返すのみであり,詳細なエラー情報を得るには別個の関数が必要となりました。旧バージョンで存在した API は SQLError()。非常に分かりやすくて萌えです。しかし昨日も例示した通り,ODBC はバージョン 3 からなんだか新しい API に置き換える動きが出てきており,SQLError() も別の API に置き換えられています。

新しい API は SQLGetDiagRec()SQLGetDiagField()。名前から Error という文字が消えてしまって萎え。もはや一見しただけではこれがエラー情報を返す API であるとは気づきません。

さて使用方法ですが・・・SQL を実行した後のエラーについては前述の MS のドキュメントをご覧ください。問題なのは,昨日までに例示したような各種ハンドル割り当て時のエラー情報の取得なんだけど,これが本当に SQLGetDiagRec() を使ってよいものかどうかハッキリした情報を見つけられませんでした。でも期待通り動いているようには見えます・・・。

// DBC ハンドルを得ようとして・・・
  rc = SQLAllocHandle(
                  SQL_HANDLE_DBC,
                  (SQLHANDLE ) env_handle,
                  (SQLHANDLE*)&dbc_handle );

    // 失敗すればそれは ENV ハンドルに問題があるから
    // という事で,ENV ハンドルにまつわるエラー情報を得ます

    if ( ! RET_SUCCESS(rc) ) {

      SQLCHAR buf5[6] = {0};
      SQLINTEGER code = 0;
      SQLCHAR msg[2049] = {0};
      SQLSMALLINT ret = 0;

      SQLGetDiagRec(SQL_HANDLE_ENV,
              env_handle, 1, buf5, &code, msg, 2048, &ret);

      puts( msg );
      return FAILURE;
    }

注意しないといけないのは SQLGetDiagRec() 第 3 引数 RecNumberこれは 1 から数え始めます。0 を入力しても何も起きやしません。C/C++ を扱うプログラマの多くは「序列は 0 から始まるっ」と脳の中に回路が形成されているため,このあたりでつまづくかも知れません。

疲労度:26

2002-09-06

[ODBC] 接続時 "FOT" の続き 〜 新 API を使ってみるテスト

ODBC はもはや昨日のコードのような API は推奨しません。バージョン 3 からは次のようなコードを書きます・・?

// このコードはアレが足りません

#include <windows.h>
#include <stdio.h>
#include <sql.h>

inline bool RET_SUCCESS( SQLRETURN r ) {
  return (r == SQL_SUCCESS) || (r == SQL_SUCCESS_WITH_INFO);
}

// 各自で書き換えてください
#define SVR "K-M DB Server"
#define USR "kuriminima"
#define PWD "fakSe49z"

int main() {

  SQLRETURN r;
  SQLHENV   env_handle = 0;
  SQLHDBC   dbc_handle = 0;

  // SQLAllocEnv は次のように置き換えられます
  r = SQLAllocHandle(
              SQL_HANDLE_ENV,
              SQL_NULL_HANDLE,
              (SQLHANDLE*)&env_handle );
    if ( ! RET_SUCCESS(r) ) {
      puts("can't allocate env handle.");
      goto finally_;
    }

  // SQLAllocConnect は次のように置き換えられます
  r = SQLAllocHandle(
              SQL_HANDLE_DBC,
              env_handle,
              (SQLHANDLE*)&dbc_handle );
    if ( ! RET_SUCCESS(r) ) {
      puts("can't allocate dbc handle.");
      goto finally_;
    }

  // 接続時は何ら変更はありません
  r = SQLConnect(dbc_handle,
              SVR, SQL_NTS, // NTS = Null Terminated String
              USR, SQL_NTS,
              PWD, SQL_NTS );
    if ( ! RET_SUCCESS(r) ) {
      puts("SQLConnect failed.");
      goto finally_;
    }

  // ここに到達すれば今日の分は成功・・なんだけど
  // 上記までのコードには足りないモノがあるので・・
  puts("OK.");

  SQLDisconnect(dbc_handle);

finally_:
  // それぞれのハンドルの開放は次のように置き換えられます
  if (dbc_handle)  SQLFreeHandle( SQL_HANDLE_DBC, (SQLHANDLE)dbc_handle);
  if (env_handle)  SQLFreeHandle( SQL_HANDLE_ENV, (SQLHANDLE)env_handle);

  return 0;
}

このコードを実際に実行するとおそらく失敗するはずです。これはたまに忘れて嵌ってしまいますが,とある関数 ── SQLSetEnvAttr() が必要です。この関数は ENV ハンドルにバージョン情報を与えるために使うらしいのですが,実はこれが必要になった経緯がぜんぜん分かっていません。だから現在の私には「単なるおまじない」ほどの価値しかないんですよね。どこかにいいリソースが転がってないかな・・・

ともかく,こんなコードになります。

// 途中からを示します

  // env ハンドルを割り当てて ..
  r = SQLAllocHandle(
              SQL_HANDLE_ENV,
              SQL_NULL_HANDLE,
              (SQLHANDLE*)&env_handle );
    if ( ! RET_SUCCESS(r) ) {
      puts("can't allocate env handle.");
      goto finally_;
    }

  // SQLSetEnvAttr は,env ハンドルを割り当てた直後に呼び出します
  r = SQLSetEnvAttr(
              env_handle,
              SQL_ATTR_ODBC_VERSION,
              (void*)SQL_OV_ODBC3,
              0 );
    if ( ! RET_SUCCESS(r) ) {
      puts("can't set attr for env.");
      goto finally_;
    }

注意しなければならないのは,これを単純にコード内に混ぜるだけではいけないということ。定数 SQL_ATTR_ODBC_VERSIONSQL_OV_OSBC3 はヘッダファイル SQLEXT.H で宣言されており,別個にこれも include してやる必要があります。

// 冒頭の部分
#include <windows.h>
#include <stdio.h>
#include <sql.h>
#include <sqlext.h> // <-これが重要

とりあえず以上で接続までは成功するはずです。しっかし SQLAllocHandle() を ENV にも DBC にも使い回すとは。。。MS の大好きなやり方ですねえ。

疲労度:10

[ 使いまわす ]
あと,SQLAllocHandle() 関数は STMT ハンドルの割り当てにも使います。MS の趣味炸裂っ!

落とし穴に落ちたー

実は昨日のコードからして注意すべき重要な部分があったりして。

まず Windows 上で開発する場合,sql.h を include する前に windows.h を include する必要があります。なぜならば sql.h は,例えば内部で 「HWND 型」というシンボルを使っているからです。MS はウィンドウハンドルなんてモノを ODBC の何に使うつもりなんやろうね・・・

それから SQLConnect() の第 2,4,6 引数には普通の文字列を簡単には渡せません。普通 C/C++ コンパイラは "このような" 文字列リテラルは const char * 型みたいな感じに扱いますが,SQLConnect() に渡すべき文字列の型は SQLCHAR * 型。これは必ずしも const char * 型と同一ではありません。実際,VC++5.0 の ODBC ライブラリでは SQLCHAR = unsigned char であるため,SQLCHAR * 型への明示的なキャストがなければコンパイルできません。特別な変換関数などは必要はないようですが,少なくとも SQLCHAR* 型への明示的なキャストは必須と考えておくべきです。

なんとなく MS はこのあたりの設計があまり上手くない気がするんですが,どうなんだろう?

2002-09-05

[ODBC] 接続時の "FOT"

FOT とは何でしょう? 正解は,今私が 5 秒くらいかけて思いついた新語で Frequency Occurred Trouble の略です。よく起こるトラブル。

ODBC を用いた DB の接続方法についてはネット上に散らばっているので,かき集めるのにはちょっと苦労するかも知れませんね。素直にコーディングすれば下記のようになります。とりあえず SQL.H というファイルをインクルードしますか。

#include <windows.h>
#include <stdio.h>
#include <sql.h>

// 戻り値のチェックは次の関数がよく用いられます
inline bool RET_SUCCESS( SQLRETURN r ) {
  return (r == SQL_SUCCESS) || (r == SQL_SUCCESS_WITH_INFO);
}


// データソース .. 各自で書き換えてください
#define SVR "K-M DB Server"
#define USR "kuriminima"
#define PWD "fakSe49z"

// このコードは実際に ODBC を通じて DB に接続するまでを行います
// ただし,これらの API は推奨されていません ( 解説は後ほど )

int main() {

  SQLRETURN r;
  SQLHENV  env_handle = 0;
  SQLHDBC  dbc_handle = 0;

  r = SQLAllocEnv( &env_handle );
    if ( ! RET_SUCCESS(r) ) {
      puts("SQLAllocEnv failed.");
      goto finally_;
    }

  r = SQLAllocConnect(env_handle, &dbc_handle);
    if ( ! RET_SUCCESS(r) ) {
      puts("SQLAllocConnect failed.");
      goto finally_;
    }

  r = SQLConnect(dbc_handle,
          (SQLCHAR*)SVR, SQL_NTS, // NTS = Null Terminated String
          (SQLCHAR*)USR, SQL_NTS,
          (SQLCHAR*)PWD, SQL_NTS );
    if ( ! RET_SUCCESS(r) ) {
      puts("SQLConnect failed.");
      goto finally_;
    }

  // ここに到達すれば今日の分は成功です
  puts("OK.");

  SQLDisconnect(dbc_handle);

finally_:
  if (dbc_handle)  SQLFreeConnect(dbc_handle);
  if (env_handle)  SQLFreeEnv(env_handle);

  return 0;
}

まずこのあたりが基本形。しかし ODBC ver 3 以降ではこれらの API は非推奨となりました。ではどのような API を使うのか? 正解は明日に。

眠さの凄さ度:7908

2002-09-04

再現不能なんですけど

1 ヶ月以上前になりますが,GetModuleHandle() が正常に動かなくて困った事がありました。2002-07-28 を参照ね。問題のコードを簡略化すると,次の通り。

#include <windows.h>
#include <stdio.h>

int main() {
  if ( GetModuleHandle("kernel32.dll") ) {
    puts("OK.");
  }else{
    puts("NG.");
  }
  return 0;
}

確かにあの日,このコードで NG. を出力しました。間違いじゃないと信じています。でも今日このコードを走らせるとなぜか ( 本来は当然なんだけど ) OK. を出力してくれました。つまり kernel32.dll のモジュールのハンドルが正常に取得できたわけですね。

この 1 ヶ月の間にハードウェアの構成やソフトウェアの状況もちょっと変わったんで,もはやあの当時の状況を再現することができなくなりました。一体あの日,何が起きていたんでしょうね。。。?

ちなみに 2002-07-28 では最終的に GetWindowModuleFileName() のエントリポイントを得るのが目的だったんですよね。kernel32.dll のモジュールハンドルは無事に得られたのですが,やはりあの関数のエントリポイントは得られませんでしたとさ。

疲労度:45

[ GetModuleFileName() ]
ウィンドウハンドルから実行ファイル名を得る関数。ただし Windows2000 からのみ実装されているとか? わりと便利そうなのになあ。。。

2002-09-03

やっぱり復活しました

に HDD をダメにした時は結局 HDD の余力でデータを復活させることができました。しかし今回は前回のようにはいかないと諦めていました。なぜならば,一切が読めなくなった CD には余力も何もないからです。そしてこれはきっとハード的で物理的な問題のはず。私には手が出せないだろうことは想像に難くありません。

とは言いつつ,なんとなく会社に CD を持って行ってみたんですよね。これもやっぱり「プログラマの勘」かと。

あっ,読めるしっ!!!!1234ご

原因はよく分かりません。しかし私個人所有の 4 台の CD ドライブで何も読めなかったものが,会社のメーカー不明のドライブではほぼ完全な形で ( ディレクトリ構造だけは完全に ) 読む事ができたのです。

私が保有するマシンには Window95 もしくは WindowsMe がインストールされています。そして会社のマシンには Windows2000 が。もしかしたらハードの差ではなく OS の差によって「読める/読めない」が分かれてしまうのでしょうか? 今はちょっと追求する手段がないんですが,要するに私のマシンに Windows2000 を導入してみろってことですよね。どうしようかなー。

とりあえず,傷もついていない CD が突然読めなくなって困ってる人にはちょっと朗報かも? ソフトウェア的に何とかなるかも知れないモノのようです。

ハッピー度:1405819358255

2002-09-02

記憶媒体トラブルはまだ続くですよっ

っくりです。ていうか CD-R が読めなくなったんですが・・・

普通は CD の表面に傷がつきまくるとその CD は読めなくなるんですよね。あと,紫外線に当てまくると CD-R が読めなくなるという話を聞いた気もします。それからトラックの最内周部分だと,ちょっと傷が付いただけでもダメになる可能性が高いから要注意,とかね。

しかし私の CD-R は一味違いました。傷は一切ついていません。紫外線に当てた記憶もありません。残るは最内周部分ですが,少なくとも目に見えるナニカは全く見当たりません。

なぜこれが読めませんか。

裕福というわけではないはずの私の部屋にはなぜか CD ドライブが計 4 台もあります。全てで試してみましたが,まさに全滅でした。これは致命的なナニカが起きた事を意味します。おそらくこの CD は復活することはないでしょう。何を記録していたか詳細には思い出せないけど,

さようなら,過去の遺産たち・・・

というわけで教訓:本当に重要なデータは必ず 2 個体以上の記憶媒体に保存しておきましょう。どんなに丁重に記憶媒体を保管していても・・いや,「丁重な保管」なぞあり得ません

先日は HDD を失いましたが,データは復活しました。でも今日の CD はダメだろうな・・ショックが大きいので今日はこれまで・・

2002-09-01

もういくつ寝ると秋

度計を買いました。部屋の温度は確かに 38 度に達しています

気温と暴動の相関関係について調査を行ったのは Baron さんと Ransberger さん。アメリカ国内の暴動を調べてみた結果,27 度〜 29 度前後で暴動が多発していたとか。36 度〜 38 度では,もうすでに暴動を起こす気力もなくなるようです

k|m は心理学ショートショートのメールマガジンを購読しています。

国会 Web Archive

国会図書館が「.jp ドメインのウェブサイトの保存を始めるよー」と発表したニュース,もうご存知ですか? 国会図書館の内部には /.jsourceforge2ch を巡回するのが日課である人間が居るはずです。絶対

そういえば WayBack Machine というものがあります。それから google にもキャッシュ機能が。これらについて当初は「著作権的にヤバいんでは」と物議を醸していましたが,結局みんな黙認しちゃってます。「サイトを見た客から直接代金を貰う」ような商売を誰もやっていない or それを行うのであれば通常の方法では接続できない仕組みを採用しているのと,ページをそのまま保存するのであれば「同一性の保持」には問題が少ないからかな。それに,いちいち文句をつけても面白くないですもんね。

実際,このようなページのキャッシュによって私は何度かプログラマ生命を助けられたという経験があります。k|m は国会図書館を応援しようと思います。まじで。

[ 国会図書館 ]
国立国会図書館。「利用上の注意」を見ると リンクする時は IP アドレスじゃなくて URL の方がいいよ とさえ書いてあるのでますます萌え。そこらのサイトよりも「おお,分かってるなあ」ていう感じします。
[ /.j ]
さすがに "「恥ずかしいまでに技術に疎いお役所」嫌い" な人が集まってるだけあり,件のストーリーではなかなか厳しい意見も出てます。でも私は国会図書館について好意的に捕らえたいな。WayBack Machine や Google がやっているのと同程度に,良識をもって今回の作業を行っていくんだと思いますよ。
Written by kuri|minima(tkuri@fat.coara.or.jp) - all rights reserved.(warai
このリソースの位置情報は http://www.coara.or.jp/%7etkuri/D/014.htm で安定しています。秋目前です,coara さんっ