プログラムが書いたとおりに動かないという現象が起きて、「D言語わけわかんねー」ってなっていたんですが、とある本を読んで解決しました。
具体的には、D言語の標準出力関数writeではプログラムが停止し、writelnでは問題なく出力されるというものです。両関数の違いは単に改行があるかないかです。
C言語をバリバリ使っている人なら、これだけの説明ですぐに原因がわかるんでしょうが、私はほとんどがC#でしたのでこんな現象初体験です。
そして、たまたま読んでいた本、『センス・オブ・プログラミング!』前橋和弥 著―を読んでいなければ原因が分からず、dmdのバグと解釈してD言語を諦めていたことでしょう。
詳しい話は続きから。
さて、おそらく原因となったのはバッファリングという仕組みです。
コンソールに出力するという入出力関係の処理は、通常の処理に比べて時間がかかります。そこで、出力するものをある程度溜めておいて、一気に出力することで、処理速度を向上させることができます。このときのある程度溜めておいて一気に出力することをバッファリングと言います。
バッファリングを体感してみましょう。といっても単に私が発生させたD言語のバグです。今限定のバグだと思います。Windows限定です。
"sample7.d"
import std.stdio; //write
import std.c.windows.windows;
void main(){
HANDLE ih = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD *ir = new INPUT_RECORD;
uint n = 0;
while(true){
ReadConsoleInputW(ih,ir,1,&n);
write("UnicodeChar=",cast(int)ir.KeyEvent.UnicodeChar);
}
}
D>dmd sample7.d
※このプログラムは動きません。[Ctrl+C]で強制終了してください。
というわけで、このプログラムは動きません。しかし、次のようにprintf関数を使うと動きます。
"sample7.d"
import std.c.stdio; //printf
import std.c.windows.windows;
void main(){
HANDLE ih = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD *ir = new INPUT_RECORD;
uint n = 0;
while(true){
ReadConsoleInputW(ih,ir,1,&n);
printf("UnicodeChar=%d",ir.KeyEvent.UnicodeChar);
}
}
あるいは、改行して出力するwriteln関数を使うと動きます。
"sample7.d"
import std.stdio; //write
import std.c.windows.windows;
void main(){
HANDLE ih = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD *ir = new INPUT_RECORD;
uint n = 0;
while(true){
ReadConsoleInputW(ih,ir,1,&n);
writeln("UnicodeChar=",cast(int)ir.KeyEvent.UnicodeChar);
}
}
根本的な原因はわかりませんが、バッファリングの関係で何らかのバグがあるということが推測できます。
ところで、「sample7って何?」って思いませんか。これは、非常によく使うプログラムでして、テキストエディタ製作記2で作りました。コンソールからの入力を知るためのプログラムです。あまりによく使うため、サンプルの番号まで覚えてしまいました。
このバッファリングを知ることになった前橋和弥さんの本を読んでいたのは実は全くの偶然ではありません。前回の記事でint (*)intという型の解釈の仕方が同氏の『C言語 ポインタ完全制覇』という本に書いてあったような気がしたので参照してみて、その流れで『センス・オブ・プログラミング!』を読みました。
『センス・オブ・プログラミング!』は、プログラミング入門書ではありません。一通り入門を終えた人が読む本です。これに書いてあることは、私はいくつかプログラムを書くうちに習得していたものですから、私にとってはあんまり役に立ちませんでした。だだし、著者はC言語にとても詳しいようで、C言語のディープな知識を勉強したい人にはおすすめです。
0 件のコメント:
コメントを投稿