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

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

ただいまの
回答率

87.96%

C言語 Sレコードをバイナリ変換

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 1,976

score 109

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

#define  ROWREADMAX 256 //一行の読み込み最大文字数
#define BUFFER 1024  
#define ADDRESSBYTE2 2
#define ADDRESSBYTE3 3
#define ADDRESSBYTE4 4
#define FILE_OPEN_ERR 0x01            //ファイルオープンエラー
#define FILE_SPECIFIED_ERR 0x02   //    ファイル指定エラー
#define OPT_ERR 0x04   //オプションエラー
//オプション
typedef  struct {

    char* infilename;
    char* outfilename;
    char  input_flag;
    char output_flag;
    char help_flag;

} opts_t;

//プロトタイプ宣言
analysis_srecord_change_binary(char readline[], FILE* wfile);
srecord_change_binary(char* ascdata);


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


    int err = 0;
    int cnt;
    FILE* file;

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

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

            case'r':
            case'R':

                    if ((file = fopen(opts->infilename, "r")) != NULL) {    //ファイルがあれば
                    }
                    else {                                                                  //ファイルがなければ
                        err |=  FILE_OPEN_ERR;
                    }

                break;
            case 'i':
            case 'I':

                if (*(argv[cnt] + 2) == '=') {                         //オプションに= があった場合

                    opts->infilename = argv[cnt] + 3;
                }
                else {
                    opts->infilename = argv[cnt] + 2;
                }

                break;
            case 'o':
            case 'O':

                if (*(argv[cnt] + 2) == '=') {
                    opts->outfilename = argv[cnt] + 3;
                }
                else {

                    opts->outfilename = argv[cnt] + 2;
                }

                break;
            case '?':

                opts->help_flag = 1;

                break;

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

                err |= OPT_ERR;
                break;
            }
        }

        if (opts->infilename == NULL) {

            opts->infilename = argv[cnt];      //引数の一つ目のファイル名はインプットファイル
        }
        else if (opts->outfilename == NULL) {
            opts->outfilename = argv[cnt];  //引数の二つ目のファイル名はアウトプットファイル
        }
        else {

            err |= FILE_SPECIFIED_ERR;   //ファイル指定エラーのビットを立てる
        }
    }
    return err;
}
int main(int argc, char* argv[]) {

    opts_t opts;
    char readline[BUFFER];
    int  result = 0;

    FILE* wfile;
    FILE* file;

    //構造体の初期化
    opts.infilename = NULL;
    opts.outfilename = NULL;
    //opts.input_flag = stdin;
    //opts.output_flag = stdout;
    opts.help_flag = 0;


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

    if ((result != 0) || (opts.help_flag)) {
        if (result & FILE_SPECIFIED_ERR) {
            fprintf(stderr, "ファイル指定が3つ以上あります\n");
        }
        if (result & FILE_OPEN_ERR ) {
            fprintf(stderr, "ファイルが存在しません");
        }
        if (result & OPT_ERR) {

            fprintf(stderr, "オプションの指定が間違っています");
        }
        if (result & opts.help_flag) {

                  fprintf(stderr, "Syntax:   srec2bin[<opts>] [[/ i[=]]<inpath>] [[/ o[=]]<outpath>] [<opts>]\n");
                  fprintf(stderr, "Function : converts S record to binary file\n");
                  fprintf(stderr, "Options :\n\n");
                  fprintf(stderr, "  / r             出力ファイルが存在するとき、強制的に上書きをする。\n");
                  fprintf(stderr, " / i[=]          入力ファイルパス(デフォルト = stdin)");
                  fprintf(stderr, "  / o[=]          出力ファイルパス(デフォルト = stdout)\n");
                  fprintf(stderr, " / ? 使い方の表示\n");
        }
        return;
    }


    if ((wfile = fopen(opts.outfilename, "w")) != NULL){

    }
    else {

        fprintf(stderr,"ファイルが開けませんでした");
    }

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


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

            while (fgets(readline, ROWREADMAX, file) != NULL) {

                analysis_srecord_change_binary( readline,&wfile);
                printf("\n");
            //    puts(readline);
            }

        }
        else {                                                                  //ファイルがなければ
            fprintf(stderr, "ファイルが開けませんでした");
        return 0;
        }
    }
    else {
        file = stdin;
    }

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

    }
}


//Sレコードを解析しバイナリに変換

analysis_srecord_change_binary(char readline[], FILE* wfile) {

    int cnt = 0;
    char stype;
    int   recsize;   //レコード長
    int addsize;  //アドレスの長さ
    int datasize; //データの長さ
    unsigned char checksum = 0;
    static int row = 0;
    char bindata;


    row++;      //読み込みが何行目か

    if (readline[cnt] == 'S') {    //初めがSなら

        cnt++;

        stype = (readline[cnt]);   //タイプを格納

        switch (stype) {         //タイプによってアドレスの長さ格納

        case '0':
        case '1':
        case '9':

            addsize = ADDRESSBYTE2;
            cnt++;
            break;
        case'2':
        case'8':

            addsize = ADDRESSBYTE3;
            cnt++;
            break;
        case'3':
        case'7':

            addsize = ADDRESSBYTE4;
            cnt++;
            break;
        default:
            fprintf(stderr, "Sレコードではありません");
            exit(1);
        }

        recsize = srecord_change_binary(&readline[cnt]);  //レコードサイズを取得

        cnt += 2;
        checksum += recsize;  //チェックサムにレコードサイズの部分を足す

        for (int dcnt = 0; dcnt < addsize; dcnt++) {  //アドレスをバイナリに変換してチェックサムに足す

            bindata = srecord_change_binary(&readline[cnt]);

            checksum += bindata;

            cnt += 2;
        }

        //レコードサイズから(アドレスサイズ+1(チェックサム))を引き、データサイズを算出
        datasize = recsize - (addsize + 1);

        //cnt += addsize;    //カウントをアドレス分進める

        for (int dcnt = 0; dcnt < datasize; dcnt++) {

            bindata = srecord_change_binary(&readline[cnt]);      //データをバイナリに変換
            checksum += bindata;                                                   //2バイト進める  

            fputc( bindata, wfile);

            //printf("%c", bindata);

            cnt += 2;                                                                       
        }

        checksum += srecord_change_binary(&readline[cnt]);   //チェックサムをチェックサムに足す


        if (checksum != 0xFF) {                                                         //チェックサムでデータの確認

            printf("\n");
            fprintf(stderr ,"%d行目のデータがおかしいです\n%s",row,readline);
        }
    }
    else {
        fprintf(stderr, "Sレコードではありません");
    }
}

//Sレコードをバイナリに変換

srecord_change_binary(char *ascdata) {

    unsigned char bin_H;  
    unsigned char bin_L;
    unsigned char bin_HL;

    bin_H = (*ascdata - '0');
        if (bin_H > 9) {
            bin_H = bin_H - ('A' - ':');
        }

        bin_H = bin_H << 4;

        bin_L = (*(ascdata + 1) - '0');
        if (bin_L > 9) {

            bin_L = bin_L - ('A' - ':');
        }

     bin_HL =     bin_H |= bin_L;

     return bin_HL;
}

コマンドラインから引数をもらい、コマンドラインで渡されたファイルを別のファイルに出力したいと考えております。

上記のコードを実行すると

1:警告
C6387    'opts.outfilename' は '0' である可能性があります: この動作は、関数 'fopen' の指定に従っていません。    srecord    

対象行>>if ((wfile = fopen(opts.outfilename, "w")) != NULL){   

2:警告
C4047     '関数': 間接参照のレベルが 'FILE *' と 'FILE **' で異なっています。        164行    

対象行>> analysis_srecord_change_binary( readline,&wfile);


警告    C4024     'analysis_srecord_change_binary': の型が 2 の仮引数および実引数と異なります。        164行

対象行>>    analysis_srecord_change_binary( readline,&wfile);

と3つ警告が出てしまいます。
なかなか、理由が分からなかったのでアドバイス頂けると助かります。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

0

1:警告
C6387    'opts.outfilename' は '0' である可能性があります:

引数の指定次第では、opts.outfilename がセットされず、NULL のままの可能性がある。

あとは、Bullさんの指摘通り、
analysis_srecord_change_binary()の第2引数は、 FILE * が必要であるが、&wfile なので、 FILE **である。

ちょっと気になったのが、srecord_change_binary() の戻り値の宣言がありません。unsigned char で宣言しましょう。また、戻り値が無い場合は、voidです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/08/23 09:48

    ありがとうございます。
    勉強になりました。

    キャンセル

0

C6387    'opts.outfilename' は '0' である可能性があります: 

opts.outfilenameがNULLなんでしょう
その他の警告は、出ている文章のとおりなので、それを読んでください

で、C言語のコードを組むのなら、VisualStudioやEclipseなどのデバッグできる環境を整えましょう。
任意のソース業で実行を止め、変数の内容を見たり、1行づつ実行したりできます
そうすれば、当てずっぽでコードを書かなくて済むようになります

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

コードを詳細に見てませんが、二つ目と三つ目の警告は

analysis_srecord_change_binary(readline, wfile);


とすれば消えるはずです。
この警告は致命的なので直さなければなりませんが、最初の警告は余り気にしなくても良いかもしれません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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