質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.34%

C言語 dumpコマンド作成 file読み込みが上手くいかない

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,127

score 109

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma warning(disable: 4996)

#define H_PRT 0x02// ヘッダ印字オプション 
#define C_PRT 0x01// 文字印字オプション
#define ROW 16 // 1行に表示する文字
#define TEXTBUF 16 //テキストファイル用のバッファ
#define  FILE_ERR 10// 
#define OPT_ERR 10


//オプション
typedef  struct {

    char* infilename;
    char prt_charflag;
    char prt_headerflag;
    char prt_help;
    int offsetval;
    int filecheck;
    int optcheck;
} opts_t;

//プロトタイプ宣言
void dump(unsigned char* staddr, int dsize, opts_t* opts);

//オプションの解析
int opts_analisys(int argc, char* argv[], opts_t* opts) {

    int cnt;
    int err = 0;
    for (cnt = 1; cnt < argc; cnt++) { //引数の数ループ
        if (*argv[cnt] == '/') {   //引数の最初の文字が/なら

            switch (*(argv[cnt] + 1)) {

            case'H':
            case'h':

                opts->prt_headerflag = 1;  //16行毎にヘッダーの出力 prt_headerflag; = 1

                break;
            case 'c':
            case 'C':

                opts->prt_charflag = 1;    //ダンプのあとに文字を表示

                break;
            case 'o':
            case 'O':
                opts->offsetval = 1;

                break;

            case '?':
                opts->prt_help = 1;
                break;

            default:    //オプションが無いとき、エラー

                opts->optcheck = OPT_ERR;
                err = OPT_ERR;   //opt err

                break;
            }
            continue;
        }
        if (opts->infilename == NULL) {
            opts->infilename = argv[cnt];  //ファイル名をopts.infilename へ
        }
        else {

            opts->filecheck = FILE_ERR;
            err = FILE_ERR;

            return err;
        }
    }
    return err;
}

int main(int argc, char* argv[]) {


    char bin_data[TEXTBUF]; // テキストファイル読み込み用
    int readnum;
    opts_t opts;
    int result = 0;

    //構造体の初期化
    opts.infilename = NULL;
    opts.prt_charflag = 0;
    opts.prt_headerflag = 0;
    opts.prt_help = 0;
    opts.offsetval = 0;
    opts.filecheck = 0;
    opts.optcheck = 0;

    FILE* file;

    result = opts_analisys(argc, argv, &opts);  //オプションの解析

    //if(ファイルエラー   または  オプションで?)
    if (((result & opts.filecheck) != 0) || ((result & opts.optcheck) != 0) || (opts.prt_help == 1)) {

        if ((result & opts.filecheck) != 0) {
            fprintf(stderr, "ファイル指定が2つあります");
        }
        if ((result & opts.optcheck) != 0) {

            fprintf(stderr, "オプション指定が間違っています");
        }
        if (opts.prt_help == 1) {
            fprintf(stderr, "構文:  mydump[<opts>] [<inpath>] [<opts>]\n機能:  ファイルやデバイスの内容を16進で表示する\nオプション:\n/ o[=]<hex> オフセットアドレスの指定(省略の場合は0000)\n/ h       16行毎にヘッダーの出力(デフォルトは = 0)\n    / c      ダンプのあとに文字を表示(デフォルトは = 1)\n / ?   使用方法の表示(このメッセージを表示)");
        }
        return 0;
    }

    if (opts.infilename != NULL) {      //コマンドラインからファイルの入力があれば


        if ((file = fopen(opts.infilename, "rb")) != NULL) {    //ファイルがあれば

            fseek(file, opts.offsetval, SEEK_SET);
        }
        else {                                                                  //ファイルがなければ
            fprintf(stderr, "ファイルがありません");
            return 0;
        }
    }
    else {
        file = stdin;    
    }

    while ((readnum = fread(bin_data, sizeof(unsigned char), TEXTBUF, file)) > 0) {

        dump(bin_data, readnum, &opts);
    }

    if (opts.infilename != NULL) {
        fclose(file);    //ファイルが開かれたらクローズ
    }
}
//印刷
void  dump(unsigned char* staddr, int dsize, opts_t* opts) {

    int startcnt = 0;// ダンプするバイト数のカウント
    int bytecnt; // 16回ループさせる
    int savecnt;
    static int address = 0; //アドレスの表示
    static int onhold = 0; //文字出力が最後のバイトだった時の一時保留

    static  int headercnt = 0;

    char addrhead[] = "Addr";
    char hexa[] = "0 1  2 3  4 5  6 7  8 9  A B  C D  E F";
    char charprint[] = "0 2 4 6 8 A C E";

    while (startcnt < dsize) {

        if (onhold != 0) {  //前回最後が漢字だった場合、漢字を出力して改行

            printf("%c%c\n", onhold, staddr[startcnt]);
        }

        //初回ヘッダー表示 opt & H_PRT == 0だった時は16行毎にヘッダー表示
        if ((headercnt == 0) || ((opts->prt_headerflag & H_PRT) == 0) && (headercnt % ROW == 0)) {
            //16行毎にヘッダー

            printf("  %s     %s  ", addrhead, hexa);


            if ((opts->prt_charflag & C_PRT) != 0) {  //opt が文字表示の場合 文字ヘッダー表示

                printf("%s", charprint);
            }

            printf("\n");
            printf("--------  ---- ---- ---- ---- ---- ---- ---- ----");

            if ((opts->prt_charflag & C_PRT) != 0) { ////opt が文字表示の場合 文字罫線表示
                printf("  ----------------");

            }
            printf("\n");
        }

        headercnt++;

        printf("%08x  ", address);

        savecnt = startcnt;
        for (bytecnt = 0; bytecnt < ROW; bytecnt++) {

            if (startcnt < dsize) {
                printf("%02x", staddr[startcnt]); //16進数で出力
            }
            else {
                printf("  ");
            }
            if (startcnt % 2 != 0) {
                printf(" ");
            }
            startcnt++;
        }

        //文字の出力

        if ((opts->prt_charflag & C_PRT) != 0) {   //optで文字表示の場合 表示

            startcnt = savecnt;
            printf(" ");

            for (bytecnt = 0; bytecnt < ROW; bytecnt++) {

                if (onhold != 0) {  //前回最後が漢字だった場合 次の行の最初にスペースと初期化

                    printf(" ");
                    onhold = 0;
                    bytecnt++;
                    startcnt++;
                }

                if (startcnt < dsize) {

                    //漢字だった場合
                    if ((staddr[startcnt] >= 0x81 && staddr[startcnt] < 0xa0) || (staddr[startcnt] >= 0xe0 && staddr[startcnt] < 0xfd)) {

                        if (bytecnt < ROW - 1) {  //最後のバイトでなければ

                            printf("%c%c", staddr[startcnt], staddr[startcnt + 1]);
                            startcnt++;
                            bytecnt++;
                        }
                        else {//漢字で最後のバイトの場合、保留

                            onhold = staddr[startcnt];
                        }
                    }
                    else {

                        if ((staddr[startcnt] >= 0x20 && staddr[startcnt] < 0x7f) || (staddr[startcnt] >= 0xa0 && staddr[startcnt] < 0xe0)) {

                            printf("%c", staddr[startcnt]);
                        }
                        else {
                            printf("");
                        }
                    }
                }
                else {
                    printf(" ");
                }

                startcnt++;
            }
            if (onhold == 0) {  //最後が漢字でなければ改行
                printf("\n");
            }
        }
        else {  //optが文字表示ではない場合 改行

            printf("\n");
        }
        address += ROW; //addressを出力しただけ足す
    }
}

上記のコードをコマンドラインから実行しても、エラーも出力も何もでません。

/?  や ファイル名を複数入力した場合、オプションの解析でエラーがでるので

    if (opts.infilename != NULL) {      //コマンドラインからファイルの入力があれば


        if ((file = fopen(opts.infilename, "rb")) != NULL) {    //ファイルがあれば

            fseek(file, opts.offsetval, SEEK_SET);
        }
        else {                                                                  //ファイルがなければ
            fprintf(stderr, "ファイルがありません");
            return 0;
        }
    }
    else {
        file = stdin;    
    }

    while ((readnum = fread(bin_data, sizeof(unsigned char), TEXTBUF, file)) > 0) {

        dump(bin_data, readnum, &opts);
    }

    if (opts.infilename != NULL) {
        fclose(file);    //ファイルが開かれたらクローズ
    }
}

ここの部分に問題がある気がするのですが、なかなか解決できません。  
ご指摘いただけると幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tatsu99

    2019/08/19 16:38 編集

    pathを通してOKとなるのは、実行ファイルに対してです。
    ダンプ対象のファイルは、フルパスで指定するか、そのファイルがあるフォルダまで移動して、コマンドを打たないとだめです。そもそも、そのあたりの事情が不明なので、まずは、確実に成功する方法として、
    実行ファイルとダンプ対象のファイルを同じフォルダに格納し、そのフォルダでコマンドを実行してくださいと書きました。この方法で、「ファイルがありません」という件をまず解決するのが先決かと。

    キャンセル

  • kokok

    2019/08/19 16:54

    ありがとうございます。

    「ファイルがありません」という件は、そのファイルがあるフォルダまで移動して実行したところ解決できました。

    キャンセル

  • tatsu99

    2019/08/19 16:59 編集

    それでは、本件は解決でしょうか。それとも、何の出力結果もなく終了してしまうということでしょうか。

    キャンセル

回答 1

checkベストアンサー

+1

VisualStudioを使ってるならデバッグしましょう。
ファイルのオープンが問題だと思うなら、そこんところにブレークポイントを設置して実行を止め、各変数の値を確認してください。また、その実行結果が何を返しているか確認しましょう。
そして1行づつ実行させ、あなたの想定から外れる動作のところを確認します

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/19 14:12

    コマンドラインから引数など渡す場合は、どのようにデバッグすれば良いのでしょうか?

    キャンセル

  • 2019/08/19 14:18

    プロジェクトのプロパティでコマンド引数の設定があります

    このコードではファイル名の設定がうまくいかないですね

    キャンセル

  • 2019/08/19 14:40

    プロジェクトのプロパティでコマンド引数の設定は一応しております。

    キャンセル

  • 2019/08/19 14:51

    ならそれでデバッグしましょうよ。
    1行づつ実行させてみたらどうですか

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る