第26章 時計の基礎 


どうも、このホーム・ページで作るプログラムはパッとしないなあ!

と、思われている方いませんか。それは、グラフィックスを全く 使っていないからです。グラフィックスを派手に使えばもう少し カッコイイプログラムができるかもしれません。 でも、あえて使っていません。それは、グラフィックスを使うと 機種とか、処理系とか諸々に依存したプログラムになるからです。 当ホーム・ページで紹介しているサンプル・プログラムはすべて マイクロソフト社のVC++1.51で作っています。しかし、当然それ以外の 処理系を使っている方も大勢いることでしょう。当ホーム・ページの サンプルプログラムはどんなコンパイラにでも(ANSI Cに準拠していれば) 手直しせずにそのまま使えるよう、あえてグラフィックスは取り上げていません。 しかし、当ホーム・ページの内容を十分理解した方であれば グラフィックスは簡単です。マニュアルやら、ヘルプを見てご自分で 挑戦してみてください。

前置きが、すっかり長くなってしまいました。今回は「時計の基礎」 です。アナログの時計は、どうしてもグラフィックスを使わなくてはならず ボツ。デジタルなら何とかできるでしょう。(また行き当たりばったりで 作ってみます。)

まずは、今の時間はどうやって調べたらいいのでしょう。

こんな時は、ヘルプです!

メニュー・バーの「Help」「C/C++ Language」「ランタイム ライブラリ」と たどっていくと何と「時間」というそのものズバリの項目が見つかりました。 これをクリックして使えそうな関数を調べてみましょう。VC++1.51では14個の 関数が見つかりました。そのうちのいくつかを見てみましょう。
#include <time.h>
time_t time(time_t *timer);

#include <time.h>
struct tm *localtime(const time_t *timer);

#include <time.h>
char *asctime(const struct tm *timeptr);
最初のtime()関数ですがこれは、もう第13章で出てきました。 1970年1月1日の0時0分0秒からの経過時間を返す関数ですね。time_tというのも すでに13章で説明済みです。忘れた人は、もう一度13章を読んでください。

次のlocaltime()関数は何をするのでしょうか。これは、time関数で得られた経過時間を 地方時間に直すものです。time関数で得られる経過時間は世界標準時間での話なので 日本時間に直す必要があるわけです。では、この関数の戻り値は一体なんでしょう? struct tmというのは、もうすでに定義されていてVC++1.51のヘルプによると次のような メンバを持ちます。

メンバー    内 容
int tm_sec    秒
int tm_min    分
int tm_hour    時間(0〜24)
int tm_mday    日付(1〜31)
int tm_mon    月(0〜11、1月を0とする)
int tm_year    年(現在の年から1900を引いた値)
int tm_wday    曜日(0〜6、日曜日を0とする)
int tm_yday    年初からの通算日数(0〜365、1月1日を0とする)
int tm_isdst    夏時間が有効な場合には0以外、それ以外の場合には0
この意味の分からない人は、第15章を参照してください。

そして、最後にasctime()関数は、localtime()関数で得られたtm構造体より、文字列を 作り出す関数と思えばよいでしょう。

これじゃ、さっぱり何のことかわからん!!!

はい、ではこれらの関数より現在の日付や時刻を表す手順を 「猫でもわかる」ように説明します。

手順1 time関数で経過時間を取得する time(経過時間へのポインター); 手順2 localtime関数で地方時間に直す tm構造体へのポインター=localtime(経過時間へのポインター); 手順3 tm構造体から文字列を得る 文字型へのポインター=asctime(tm構造体へのポインター);

この説明は、少々正しくないところがあるが・・・
ま、これで、少なくとも現在の日付や、時刻の文字列が得られるでしょう。

コメントと、上の「手順」を見比べながらじっくり見てください。 構造体へのポインターは、あとの章でまた出てきます。

現在の日付・時刻が表示されましたね。こうなれば大成功です。 今回使った3つの関数は、どんなコンパイラでもOK(の筈です)。

よーし!わかった!今のプログラムをwhile文で グルグル回しにすればいいんだ!


あー、基本的にはそうですが少し違います。 これをグルグル回しにしたらどうなるかやってみましょう。 time(&present_tm);からprintf(...)までを while(1){ }で囲んでしまうと・・・

確かに、現在の日付と時刻を表示し続けますが、 第一やめることができない。(ストップキーを押すしかない) また、表示する場所が次々と新しいところに移っている。 等々の問題点があります。(超初心者にありがち)

ではどうすればよいのでしょう。マイクロソフトの コンパイラでは、

#include <graph.h> struct _rccoord __far _settextposition(short row,short column);

というのがあって、rowとcolumnに数値を入れれば、その テキスト座標に表示することができます。 しかし、これはANSIに準拠していません。 文字に色を付けたり、カーソルを移動させたりする命令は、 ハードウェアに依存しています。ですから、 この手の関数はANSIで認めていないのです。

自分の持っているコンパイラが、どんな関数でこれを実現しているのか 調べてみてください。ここでは、もう少し別な方法を考えてみましょう。

それには、MS-DOSのエスケープ・シーケンスを使います。

これは、0x1bに続くコードを画面に送ることによって 文字の色づけ、カーソルの移動、画面消去などのある程度のことができます。 これは、OSが吸収してくれるのでMS-DOSが動いている機種ならOKです。(*注) ちなみに、0x1bの0xは16進を表す記号です。16進で1bは何を表している のでしょうか。キャラクタコード表で見ると(Esc)と書かれています。 エスケープのことです。従って0x1bに続くコードをエスケープ・シーケンス というのです。(本当かいな?)

ESC [ps; ps; ps;.....;ps m
ps属性ps属性
0デフォルト30(40)
1ハイライト31(41)
2垂線表示32(42)
4アンダーライン33(43)
5ブリンク34(44)
7リバース35(45)
8シークレット36(46)水色
37(47)

さて、具体的な使い方ですが、まず(ESC)を出力します。 それに続いて、[を出力、その後ps(表を参照)mの順に出力します。 psは、複数書いてかまいません。ESCの出力の仕方は、いろいろ考えられます。

printf("\x1b");

putchar(0x1b);

printf("%c", 0x1b);

などなど使いやすいように工夫してみてください。

エスケープ・シーケンスをいろいろな方法で書いてみました。 みなさんもいろいろな書き方を考えてみてください。

カラフルできれいですね。

次は、カーソル移動の説明です。

ESC [pl;pcH

plがy座標、pcがx座標を表します。xとyを間違えないでください。

printf("\x1b[12;10H");

とすればカーソルは、(10,12)に移動します。 これで、何とか時計らしきものが作れそうですね。 あとは、ループからの脱出方法です。 これには、よく

kbhit()関数

が使われます。 この関数はANSIで認められていませんが、たいていの 処理系で使えます。キーボードから何も入力がなければ 0を返し、何か入力があると0以外を返します。

while(!kbhit())の使い方は是非マスターしてください。

まあ、何とか目的は達成しています。しかし不満は残ります。 実際動かしてみるとわかるのですが、カーソルがうるさい、 画面がチカチカするなどです。カーソルを消すには、やはり エスケープ・シーケンスを使います。

ESC [>5h

で消えます。

ESC [>5l

で出現します。チカチカするのを止めるのは、非常に速い 速度で書き直しているからです。得られた文字列を いったん何かに蓄えておいて、次に得られた文字列と比較します。 同じであれば何もせず、違っていれば書き直しこの文字列を またどこかに蓄えておく、という作業をすればチカチカしなくなります。 ぜひ、このプログラムに挑戦してみてください。 今までの章を完全にマスターしていれば簡単にできるはずです。


(*注)同じMS-DOSでもたとえば98シリーズと FMシリーズではカラーコードが違っています。他にも微妙に違うところが あるかもしれません。お使いの機種で本章のプログラムがうまく動作しない 場合は、無視して下さい。本章以降のプログラムについても同様です。
[Index][総合Index] [Previous Chapter] [Next Chapter]

Update Nov/18/1996 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。