C言語ケーススタディ ファイルダンプコマンドの作り方2




2014年10月より個人の方を対象に、Study C無料提供を開始しました。
C言語を勉強中の方は、学習・教育に最適なC言語インタープリタのStudy Cを使ってみてください(個人の方は無料です)。
大学・高専・高校などの教育機関での採用実績も多数あるロングセラー商品Study Cが、個人向けに無料提供を始めました。
インタープリタの手軽さに加え、ゲームや3Dタートルグラフィックで楽しく勉強したりと、C言語の学習を強力にサポートします。
ブロック崩しゲーム 3Dツリー クリスマスツリー
また、このようなボタンの用意されているページでは、掲載しているプログラムをStudy Cに直接ロードし実行したりすることができます。
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する
Study C無料利用についての詳細は、このページを参照してください。



dump hello.c

---------------hello.c--------------
00000000  6D 61 69 6E 28 29 0D 0A-7B 0D 0A 09 70 72 69 6E   main()..{...prin
00000010  74 66 28 22 68 65 6C 6C-6F 22 29 3B 0D 0A 7D 0D   tf("hello");..}.
00000020  0A 1A                                             ..

今回はダンプコマンドが表示する右側の文字の部分を作成します。
(1)右側の文字は16バイト分のデータを表示してから出力(表示)する必要があるので一旦変数に保持している必要があります(buffという配列にデータを保持します)。
(2)配列にはASCIIコード0x20から0x7Eまでを代入してそれ以外のコードは表示できないため'.'を代入します。
(3)配列の内容は内側のループから抜ける度に表示します(配列の最後に'\0'を代入する必要があります)。
#include <stdio.h>

main()
{
        FILE    *fp;
        int     data;

        int     i1;

        unsigned long
                addr;

        char    buff[100];

        fp = fopen("hello.c", "rb");
        if(fp == NULL){
                printf("ファイルがオープンできません.\n");
                return;
        }
        for(addr = 0; ; addr += 16){
                printf("%08lX  ", addr);

                for(i1 = 0; i1 < 16; i1++){
                        if((data = getc(fp) ) == EOF){
                                printf("\n");
                                fclose(fp);
                                return;
                        }

                        if(data < 0x20 || data >= 0x7F)
                                buff[i1] = '.';
                        else
                                buff[i1] = data;
                        printf("%02X ", data);
                }
                buff[i1] = '\0';
                printf("  %s\n", buff);
        }
}
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する ブラウザとの連携機能が使用可能なStudy Cのバージョンなどについて...
このプログラムで表示はかなり最終目標に近くなったのですが、このプログラムでは最後の行だけ右側の表示が行われません。 これはgetcの結果がEOFの場合buffに残っている内容を出力せずに終了してしまうからです。 この問題はEOFでリターンしてしまう前にbuffの内容を表示すれば解決します。
#include <stdio.h>

main()
{
        FILE    *fp;
        int     data;

        int     i1;

        unsigned long
                addr;

        char    buff[100];

        fp = fopen("hello.c", "rb");
        if(fp == NULL){
                printf("ファイルがオープンできません.\n");
                return;
        }
        for(addr = 0; ; addr += 16){
                printf("%08lX  ", addr);

                for(i1 = 0; i1 < 16; i1++){
                        if((data = getc(fp)) == EOF){
                        /*** ここでbuffの内容を表示する ***/
                                buff[i1] = '\0';
                                printf("  %s\n", buff);
                                fclose(fp);
                                return;
                        }

                        if(data < 0x20 || data >= 0x7F)
                                buff[i1] = '.';
                        else
                                buff[i1] = data;
                        printf("%02X ", data);
                }
                buff[i1] = '\0';
                printf("  %s\n", buff);
        }
}
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する ブラウザとの連携機能が使用可能なStudy Cのバージョンなどについて...
上記のプログラムでもまだ問題があります。右側に表示する部分が最後の行だけちゃんと表示されません。 これは途中に空白を何個か表示することで解決できます。
次のプログラムではEOFに達したときにforループで空白を表示させています。forループ内にi1 = 0という式がないのがポイントです。 i1には、それまでに表示したデータの数(0-15の間で)が保持されているのでそのまま0に戻さずにループを続ければ空白を適切な数だけ表示させることができます。
#include <stdio.h>

main()
{
        FILE    *fp;
        int     data;

        int     i1;

        unsigned long
                addr;

        char    buff[100];

        fp = fopen("hello.c", "rb");
        if(fp == NULL){
                printf("ファイルがオープンできません.\n");
                return;
        }
        for(addr = 0; ; addr += 16){
                printf("%08lX  ", addr);

                for(i1 = 0; i1 < 16; i1++){
                        if((data = getc(fp)) == EOF){
                                buff[i1] = '\0';
                        /*** ここで空白を表示する ***/
                                for(;i1 < 16; i1++){
                                        printf("   ");
                                }
                                printf("  %s\n", buff);
                                fclose(fp);
                                return;
                        }

                        if(data < 0x20 || data >= 0x7F)
                                buff[i1] = '.';
                        else
                                buff[i1] = data;
                        printf("%02X ", data);
                }
                buff[i1] = '\0';
                printf("  %s\n", buff);
        }
}
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する ブラウザとの連携機能が使用可能なStudy Cのバージョンなどについて...
次回はダンプコマンドの仕上げです。