::SetTimer() 限界値手持ちの解説書には一切載っていないので,おそらく最近追記されたものだと思われますが,MSDN で ::SetTimer() の上限値および下限値についてのコメントを見つけました。
Windows NT/2000/XP: If uElapse is greater than 0x7fffffff, the timeout is set to 1.
Windows 2000/XP: If uElapse is less than 10, the timeout is set to 10.
Windows Server 2003: If uElapse is greater than 0x7fffffff, the timeout is set to 0x7fffffff.
・・・OS によって挙動を変えたのは・・・なぜ?
dos コマンドです。
C:\WINDOWS>subst g: e:\mylib\context
これで e:\mylib\context\ ディレクトリが g ドライブのルートディレクトリに割り当てされました。私が fopen("g:\\somefile.txt", "rb"); と書けば,実際には e:\mylib\context\somefile.txt ファイルが開かれます。
これが大変便利なのはこんな時:とある大きな会社が 2 社共同で HTML を手直しする仕事をやっています。link 要素でスタイルシートのありかを指定するんだけど,こんな事を書いてます。
<link href="/css/common.css" rel="stylesheet">
スタイルシートが「ルートディレクトリの css ディレクトリ内」と指定されているのです。しかし実際の作業ディレクトリは d:\workarea\html\ の中と規定されており,当然 css もその中。彼らは HTML を cvs からチェックアウトして手直しする時に,一旦
<link href="./css/common.css" rel="stylesheet">
と css のパスの前にピリオドを付け足して作業を行い,cvs にチェックインする前にこれを元に戻すそうなのです。ちょっとした事だけど,面倒なんですよね。
しかし subst コマンドさえ知っていれば,
C:\WINNT>subst h: d:\workarea\html
これでばっちり。h ドライブを基準に作業を簡単に進める事が出来るのです。
ああ,教えてあげればよかった・・でもほら,私は本当にただの助っ人の一人に過ぎないわけで・・
( どこかの新聞社のサイトにリンク張ろうかなとも思ったけど,やっぱしやめます )
私が“ファミコン”に出会ったのは,18 年程前の事だったかな……。
実家では私の物心のつく前から……名前は忘れたけども「なんとかビジョン」のようなコンピュータゲームがありました。ゲームは取替え可能ではなく,本体についているボタンで 3 種類のゲームを切り替えます。おそらくまだ壊れていないはずなので,実家の押入れから取り出せば遊べるはずです。
「テニス」のゲーム風景。白い点をボールに見立て,ただひたすら打ち合うのです。
……そうか。今の私はずっとこうやって育ってきた結果なんですね。
久しぶりに“ファミコン”をやってみたくなった……。去年は国内だけで 6 万台売れていたらしくて。つまり探せば……いや探す余地も無く,デパート等で簡単に手に入るはずなんですよね。
エミュレータ? ハハハ……
ポータブルなファミコンが発売されるんですね。欲しいけども,どうしよう。
まばらなファイル(Sparse File)の恐怖 (小道具展示室 by T-MZ さん)
なんだか物凄い状況になっていますが,初めて知った事なのでメモ。
Explorer って,どれくらいまでの容量の単位表示に対応してるんでしょうね? 上記サイトのスクリーンショットでは,少なくとも "エクサ" まではちゃんと確実に対応している事が分かります。エクサの次は・・・
Computer Jargon File extracts (CHEMTUTOR)
| Z | zetta- | 1000^7 = 10^21 | ゼタ (ゼッタ) |
| Y | yotta- | 1000^8 = 10^24 | ヨタ (ヨッタ) |
| Hr | harpi- | 1000^9 = 10^27 | ハーピ |
| Gc | grouchi- | 1000^10 = 10^30 | グルーチ |
| Zp | zeppi- | 1000^11 = 10^33 | ゼッピ |
| Gm | gummi- | 1000^12 = 10^36 | グミ |
| Ch | chici- | 1000^13 = 10^39 | チキ |
・・・だそうですが,これってもう確定? まれに 1000^9 を「harpo (ハーポ)」,1000^10 を「groucho (グルーチョ)」と紹介しているリソースもありますが,それは小さい方の単位で使われるみたいですね。
おっと,SI では「ヨタ(yotta) = Y」までしか定義されていない模様。・・そもそも SI では情報量を扱う単位名が定義されていないような。・・情報量って,他の単位から説明可能な次元なのかなあ?
::SetFilePointer() をハッキリさせる 2::SetFilePointer() の第 3 引数に NULL を入れるかちゃんとしたポインタを入れるかで,この関数の挙動は変わります・・てのは当たり前なんだけど,その変化の仕方が全然感覚的でないので大変です。
昨日の IFile::seek() の仕様を変えずに FileWin32::seek() を実装するならば,まず lpDistanceToMoveHigh に NULL を与える事が考えられます。これが一番簡単な解。
別解として,こんなコードを書いてみました。
result_t FileWin32::seek( signed int32_t length,
Origin whence )
{
LONG high = 0; // 後で 64 ビット長に対応する時のために
/*** 今日のポイントはこれ ***/
if ( length < 0 ) high = ~0;
DOWRD method = (whence == BEGIN) ? FILE_BEGIN:
(whence == HERE) ? FILE_CURRENT:
FILE_END;
DWORD r = ::SetFilePointer( handle_, length, &high, method );
DWORD e = ::GetLastError();
if (r == INVALID_SET_FILE_POINTER && e != NO_ERROR)
return FAILED;
return SUCCESS;
}
シーク量がマイナスの場合は high のビットを全て立ててやります。こうする事で,64bit に合成されてもきちんと "マイナス" の値を示す事ができるのです。
::SetFilePointer() をハッキリさせる 1DWORD SetFilePointer ( HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod
);
第 2 引数 lDistanceToMove に特殊な値を入れた場合,第 3 引数lpDistanceToMoveHigh に何を入れたかによってその挙動が変わるので大変です・・てのは当然なんだけど,じゃあこんなストーリーを考えてみます。
私は,とあるプロジェクトに参加しています。今回のプロジェクトでは大きなファイルを扱う予定はありません。むしろ 64 ビット整数の存在しない環境でもコンパイルする予定があるので,大きなファイルの事を考えるべきではないのです。
ファイルのシークについて,こんな設計をしました。
/*! ファイルをシークする
* @param length 移動するサイズ,バイト単位,マイナスあり
* @param whence 基点を示す IFile::Origin 型
*/
virtual result_t IFile::seek( signed int32_t length,
Origin whence ) = 0;
// ちなみに IFile::Origin はこう
enum Origin {
BEGIN, // ファイルの最初から
HERE, // 現在の地点から
END // ファイルの最後から
};
引数 length は符号付 32 ビット整数で,引数 whence は IFile::Origin 型。whence で指定された場所を基点に length バイトだけファイルをシークします。
Windows 用に,このメソッドを次のように実装しました。
// class FileWin32 : public IFile; てな感じで継承
result_t FileWin32::seek( signed int32_t length,
Origin whence )
{
LONG high = 0; // 後で 64 ビット長に対応する時のために
DOWRD method = (whence == BEGIN) ? FILE_BEGIN:
(whence == HERE) ? FILE_CURRENT:
FILE_END;
DWORD r = ::SetFilePointer( handle_, length, &high, method );
DWORD e = ::GetLastError();
if (r == INVALID_SET_FILE_POINTER && e != NO_ERROR)
return FAILED;
return SUCCESS;
}
で,実際に使ってみたわけです。
IFile *file = new FileWin32("normal_file.dat", "rb");
/* ... ごにょごにょ */
// 現在の地点から 1 バイト戻る
result_t r = file->seek( -1, IFile::HERE );
if (r == FAILED) {
Message("失敗!!");
delete file;
return FAILED;
}
・・・一般的なファイルならばこれではほぼ確実に失敗します。失敗せずとも 1 バイト戻る事は出来ません。
将来の拡張を考えて lpDistanceToMoveHigh に仮の変数を与えてしまった事が原因です。::SetFilePointer() の第 3 引数 lpDistanceToMoveHigh に NULL ポインタを指定しないならば,::SetFilePointer() は lpDistanceToMoveHigh と第 2 引数 lDistanceToMove を合わせて 64 ビット符号付き整数と見なします。上記の例で第 2 引数に入力した "-1" とは "0xFFFFFFFF" の事。lpDistanceToMoveHigh は 0x00000000 を示してあり,2 つを合成した 64 ビット整数は "0x00000000FFFFFFFF"。これは約 4GiBytes を意味します。
要するに上記のコードで私は,ファイルポインタを約 4GiBytes ほど前方に進めようとしていた,という事になります。
これを解決するには? また明日・・・
今日はわりと祝日っぽかったのに,知らずにハローワークの前で途方に暮れていた屑人間。
ってのはどうでもいいですが,ちょっと気になった事を実験。"オーバーロードされた関数のポインタ" って,果たしてコンパイラはきちんと取ってくれるのでしょうか?
#include <iostream>
using namespace std;
typedef void (*func_t1)();
typedef void (*func_t2)(int = 222);
void func() { cout << "('-'*)" << endl; }
void func(int a = 111) { cout << a << endl; }
int main() {
func_t1 f1 = func;
func_t2 f2 = func;
f1();
f2();
return 0;
}
('-'*)
222
int 型の引数をとる関数は,その引数を省略できるという意地悪っぷり。しかもしかもtypedef された型と実際の関数で,デフォルト引数が異なりますこの鬼畜め。しかしきちんとコンパイルは通り,なんか納得できる実行結果を出力してくれました。
これは使えるかもわからんね。
C や C++ をはじめとして大抵のプログラミング言語は 7-bit ASCII コードで記述できるように設計されています。この 7-bit ASCII コードは "ISO 646-1983 Invariant" と呼ばれるコードセットのスーパーセットであり,要するに ISO 646-1983 Invariant とは ASCII コードよりも限定されたコードセット。C や C++ ではその ISO ナントカでもコードを記述できるように "Trigraph" を,特に C++ では "Digraph" なんてものまで定義されています。
Digraph, Trigraph, and Escape Sequences ( Online Documentation at CASPUR )
これを使うと
%:include <stdio.h>
%:include <stdlib.h>
int main(int ac, char *av<::>) <%
if (ac >= 3) <%
int a = atoi(av<:1:>),
b = atoi(av<:2:>);
// ビット演算による加算
printf ("%d\n", (a xor b) bitor ((a bitand b) << 1) );
%>
return 0;
%>
あ,異世界だ。
まじで。小学生とおぼしき集団が大声で話してました。
「お前さー,PS 買ったらさー,カセット何買うー?」
まだ彼らは"カセット"なるものに触れる機会があるという,何よりの証拠なのです。
カセットは永遠です。
Re:現実的対応 (/.J, "HDD の容量が少ないと訴訟")
単位の接頭辞の話題。
これを徹底させようよーという事です。てか,知りませんでした。私も長いこと web を見回っているけどこんな接頭辞を見たのは初めてだという事と,私が知る限りの雑誌でもこのような話題が取り上げられた事がないからですね。
今日からここ周辺のリソースでは Ki Mi Gi 単位表示を行っていきたいと思います。ただし浸透期間という事で,脚注をつけながら。。。
うほっ,宗教団体アーレフです。しかしそんなものに臆する事なく私はリンクを貼ってゆきたいのです。
このリソースではペンフィールドをはじめとする「偉い人」のコメントを集めて,さも「脳と意識は別物である」とは科学的に裏づけされた真理であるかのように誘導しているように見えるので注意。実際には,まだ何も分かっちゃいないんでしょう?
しかし,二元論派の学者がそれなりに存在するのは意外でした。私はなまじ「複雑系」なんてものに足を踏み入れているがために「脳ほど複雑な機械ならば,そこから『意識』なんてもんが創発されたって不思議じゃない」と考えてしまいますが,もしかしたらこれは「常温核融合さえ出来れば世界は救われる」と同じレベルの考え方なのかな。精進せねば。時間はないけど。
いつぞや「スレッドセーフ,タイムアウト付き gethostbyname()」のコードを「あとでアプする」とか言いながら,アプしていない事に気づきました。
VC++5.0 でコンパイル,動作を確認しています。実は以前のコードは無駄にスレッドを立てまくってたコードだったので,最近書き直しました。スレッドというものは 1 つ立てる毎にそれなりのスタックが必要であり,あまり嬉しくないのです。
さて hostent.cpp はなんだか無駄にごちゃごちゃしていますが,こちらはほぼ無視しても大丈夫なのです。重要なのは公開されたインタフェース hostent.hpp の方。私が HostEntry クラスに持たせたのは HostEntry サービス全体を初期化,破棄する initialize() と finalize() メソッド,それに HostEntry のコンストラクタとデストラクタ,getState(),そしていくつかのアクセサです。
こんなコードが書けます。
// Win32 の例
#define STRICT
#define _WINSOCKAPI_
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include "hostent.hpp"
void print_hostent( const HostEntry& hent ) {
int i;
// hostent::h_name
printf("name: %s\n", hent.getName());
// hostent::h_aliases
i = 0;
while (hent.getAlias(i))
printf("alias: %s\n", hent.getAlias(i++));
// hostent::h_addr_type
printf("addrtype: %d\n", hent.getAddrType());
// hostent::h_length
printf("length: %d\n", hent.getLength());
// hostent::h_addr_list
if (hent.getLength() == 4) {
i = 0;
while (hent.getAddr(i)) {
in_addr ipaddr;
memcpy(&ipaddr, hent.getAddr(i++), 4);
printf("addr: %s\n", inet_ntoa(ipaddr));
}
}
}
int main( int ac, char *av[] ) {
// winsock と HostEntry サービスの初期化処理
WSAData _wsa_data;
int r = ::WSAStartup( MAKEWORD(2,0), &_wsa_data );
HostEntry::initialize();
// このスコープ指定が必要
{
HostEntry h1("www.google.com");
HostEntry h2("66.218.71.91"); // yahoo.com 逆引き
HostEntry h3("www.2ch.net");
HostEntry h4("notexists.net");
/* 最後のはホスト解決してやんない :)
* このままオブジェクトを破棄すれば,処理をキャンセルした事になる
*/
while (h3.getState() == HostEntry::WAITING)
::Sleep(1);
print_hostent(h1); puts("--------------------");
print_hostent(h2); puts("--------------------");
print_hostent(h3);
}
/* HostEntry サービスと winsock の終了処理
* 20秒待ってもスレッドが終了しなければ,強制終了させる
*/
HostEntry::finalize( 20000, true );
::WSACleanup();
return 0;
}
注意しないといけないのは,HostEntry::finalize() を呼び出すまでに全ての HostEntry インスタンスが破棄されていなければならない事。HostEntry が保有している某インスタンスのデストラクタに,クラス共通のクリティカルセクションを使っている関係で,そんな仕様になってしまいました。・・・このあたり参照カウンタでなんかを管理すればいいんでしょうが,そこまでやる事はないだろうと思ったもので。