Nodachisoft Nodachi Sword Icon
  
@あまじ✎ 2021年3月8日に更新

第2章55 バッファの利用

イチからゲーム作りで覚えるC言語
第2章54 関数ポインタと構造体を合わせて使う : PREV
NEXT : 第2章56 三角関数 :

概要

C言語のプログラムを例に、バッファを使った画面表示の高速化について確認します。

画面に表示している内容の更新やテキストデータをディスクから読み取る処理、 インターネットからダウンロードする処理は、 通常、単にメインメモリ(主記憶装置)とデータをやり取りする速度に比べて非常に遅いです。

こういった時間がかかる処理がプログラムの速度が必要な箇所に入っていると、 プログラム全体の処理速度が、遅い部分に引きずられて遅くなってしまいます。

こういった画面への表示の更新や、データをディスクから読み取るような処理は まとめてあらかじめ実施しておき、結果を高速にアクセスできるメモリの中に保存しておく、 という高速化の手法がよく使われます。

例えば、画像データはアプリを起動する時にメモリ上に読み込んでおく、 動的に形状を計算する草木の3Dデータはあらかじめ計算してメモリ上に結果を格納しておく、 ネットワーク上のデータはあらかじめダウンロードしてメモリ上に保持しておく、などです。

こういった時間のかかる処理をあらかじめ実施し、結果をため込み 処理を効率よく円滑に行うための領域をバッファ領域と呼びます。

ストリーム

C言語で文字をコンソール上(標準出力上)に表示するときにも 裏でバッファが使われています。

例えば下のようなプログラムです。

 
stdout_stream.c
printf("ABC");
printf("DE");
printf("F\nGHK");

printf("ABC"); と記述したとき、文字列「ABC」がコンソールに表示されますが、 表示するときは "A" 、 "B" 、"C" と一つ一つっ順番に表示しているわけではありません。 実際には下のように、ストリームと呼ばれるバッファ領域に表示する文字列「ABC」がたまるだけで この時点では表示されていません。 さらに続けて、printf("DE"); が実行され、これもストリームにたまっていきます。

次に printf("F\nGHK"); が実行されたとき、改行コードが入っているため、 ストリームにため込んだ文字列を、コンソール上に一気に表示するという処理が行われます。

通常、標準出力のストリームは一定以上、出力する文字がたまった時か、改行コードが 入ったときに出力されます。

いつストリームから出力するかは、使うストリームによって異なります。

標準出力のストリームがなかったら

さきほどのストリームはどのようなメリットがあるでしょうか。 画面に毎回 1 文字づつ出力していいっても、結果は変わらないように思えます。

これは、物理的に画面の表示を書き換えるという処理が、遅いため、 バッファを使うことで、高速化しています。

よくある液晶ディスプレイでしたら、1 秒感に 60 フレーム程度書き換えが可能などの 制限があります。 人の目には 1 秒間で 60 回も画面が更新されるのであれば十分と感じるかもしれませんが、 プログラムで 1 秒 60 回まで、という制限は致命的に遅いです。

1文字1文字、画面の表示を更新していたら、 原稿用紙 400 文字を表示するのに、 約 6 秒以上かかってしまうことになります。

ストリームは「ある程度、出力する内容がたまったら一気に出力する」ことで、 この問題を解決してくれています。

バッファ利用による画面更新

画像などを大量に表示するプログラムについては、 画面に表示する領域のバッファを用意し、 画像などを一度バッファ上にコピーしてから 最終的に画面に出力することが効率的です。

以下は、画面に出力する内容をバッファ領域として容易し、 バッファの中に画面に表示したい内容を書き込みをしてから、一度に出力する例です。

 
buffer_ex1.c
#include <stdio.h>
// 画面バッファをコンソール上に出力
void printScreen(char screen[]) {
    for ( int y = 0 ; y <  10 ; y++ ){
        for ( int x = 0 ; x < 30 ; x++ ){
            printf("%c",screen[y * 30 + x]);
        }
        printf("\n");
    }
}
int main () {
    // 画面バッファの宣言と初期化
    char screen[30 * 10];
    for ( int y = 0 ; y <  10 ; y++ ){
        for ( int x = 0 ; x < 30 ; x++ ){
            screen[y * 30 + x ] = '.';
        }
    }

    // 画面バッファの真ん中に書き込み
    char dialog[11 * 7] = 
        "+---------+"
        "| MENU    |"
        "+---------+"
        "| => NEW  |"
        "|    LOAD |"
        "|    END  |"
        "+---------+"
    ;
    for ( int y = 2 ; y < 2 + 7 ; y++ ){
        for ( int x = 10 ; x < 10 + 11 ; x++ ){
            screen[ y * 30 + x ] = dialog[(y-2) * 11 + (x-10)];
        }
    }
    // 出力!
    printScreen(screen);
}

実行結果は下のようになります。

実行結果
..............................
..............................
..........+---------+.........
..........| MENU    |.........
..........+---------+.........
..........| => NEW  |.........
..........|    LOAD |.........
..........|    END  |.........
..........+---------+.........
..............................

画面に出力する内容はバッファの中で編集しておき、 画面に出力するときは、一度に出力することで、 画面更新が必要なタイミングは printScreen 関数を実行する 1 度のみとなっています。

fflush 関数

標準出力などのストリームにたまったデータは、 ある程度のサイズや条件をきっかけに、たまった内容を主力します。

このようにバッファに貯まった内容を出力・反映することをフラッシュと呼びます。

この処理は通常はプログラマが意識しなくとも大丈夫ですが、 手動で、ストリームの内容を反映(フラッシュ)させたいと思うタイミングがあります。

その場合は fflush() 関数を使うことで、手動で、ストリーム内容を吐き出して更新する事ができます。

 
fflush_ex.c
#include <stdio.h>
int main(){
    for ( int c = 0 ; c < 100 * 10 ; c++ ){
        printf("X");
        // X が一文字筒画面に表示され更新される
        fflush(stdout);
    }
}

fflush 関数の引数に stdout とありますが、 これは標準出力のことで printf などで文字を出力するコンソールのことを指します。

参考として、代表的なものに下のようなストリームが指定できます。

種類 書き方
標準入力 stdin
標準出力 stdout
標準エラー出力 stderr
ファイルポインタ FILE *fp

参考

  • 特になし
イチからゲーム作りで覚えるC言語
第2章54 関数ポインタと構造体を合わせて使う : PREV
NEXT : 第2章56 三角関数 :
 
 
送信しました!

コメント、ありがとうございます。

なんかエラーでした

ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。

Twitter:@NodachiSoft_jp
お名前:
 
連絡先:
 
メッセージ:
 
戻る
内容の確認!

以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください

お名前:
 
連絡先:
 
メッセージ:
 
Roboto からの操作ではないという確認のため確認キーを入れてください。
確認キー=95
戻る
 / 
送信確認へ
コメント欄
コメント送信確認へ

関連ありそうな記事(5件)です!

第1章01 Visual Studio Community 2019 のインストール手順

#C11仕様#C言語#ゲームプログラミング✎ 2021-08-08
C言語でプログラミングをするために、無料で使える Visual Studio Community を使った開発環境を揃えていく手順や注意点をお話しています。
目次
第2章55 バッファの利用
第2章55 バッファの利用
概要
概要
ストリーム
ストリーム
標準出力のストリームがなかったら
標準出力のストリームがなかったら
バッファ利用による画面更新
バッファ利用による画面更新
fflush 関数
fflush 関数
参考
参考
Nodachisoft © 2021