1

バイナリ ファイルの長さを取得するための慣用的なスニペットがあります。

    fseek(my_file, 0, SEEK_END);
    const size_t file_size = ftell(my_file);

…ペダンティックであることfseek(file, 0, SEEK_END)は、バイナリ ストリームに対して未定義の動作をすることを知っています[ 1 ] – しかし、率直に言って、これが問題であるプラットフォームでは、私も持っていませんfstat()。とにかく、これは別の質問のトピックです…</p>

私の質問は次のとおりfseek()です。この場合、戻り値を確認する必要がありますか?

    if (fseek(my_file, 0, SEEK_END)) {

        return 1;

    }

    const size_t file_size = ftell(my_file);

このようなケースでチェックされたのを見たことがありません。また、ここでどのようなエラーが返される可能性があるfseek()のか​​も気になります。fseek()

編集:

Clifford's answerを読んだ後、ファイルのサイズを計算する際に値を処理しfseek()ftell()返す最良の方法は、専用の関数を作成することだとも思います。ただし、Clifford の良い提案ではsize_tデータ型を処理できませんでした (結局、サイズが必要です!)。そのため、最終的に最も実用的なアプローチは、ファイルのサイズを格納するためにポインターを使用し、戻り値を保持することだと思います。故障専用機能の価値。安全なサイズ計算機のためのクリフォードのソリューションへの私の貢献は次のとおりです。

int fsize (FILE * const file, size_t * const size) {

    long int ftell_retval;

    if (fseek(file, 0, SEEK_END) || (ftell_retval = ftell(file)) < 0) {

        /*  Error  */
        *size = 0;
        return 1;

    }

    *size = (size_t) ftell_retval;
    return 0;

}

そのため、ファイルの長さを知る必要がある場合は、次のように簡単に実行できます。

size_t file_size;

if (fsize(my_file, &file_size)) {

    fprintf(stderr, "Error calculating the length of the file\n");
    return 1;

}
4

4 に答える 4

3

関数の戻り値をテストし、時間どおりに処理することは常に良い習慣です。そうしないと、完全なデバッグを行わないと理解または発見できない奇妙な動作が発生する可能性があります。

fseekfseekの戻り値については、戻り値セクションの次のリンクを参照してください。

このifステートメントは、コード パイプラインでは無視できますが、問題が発生した場合の処理​​が容易になります。

于 2019-10-21T15:59:10.107 に答える
1

はい、戻り値を確認しますが、型の変更にはもっと注意してください。

size_tの範囲はより大きくても小さくてもよいことに注意してください0...LONG_MAX

// function returns an error flag
int fsize (FILE * file, size_t *size) {
  if (fseek(file, 0, SEEK_END)) {
    return 1; // fseek error  
  }

  long ftell_retval = ftell(file);
  if (ftell_retval == -1) {
    return 1; // ftell error
  }

  // Test if the file size fits in a `size_t`.
  // Improved type conversions here.
  // Portably *no* overflow possible.
  if (ftell_retval < 0 || (unsigned long) ftell_retval > SIZE_MAX) {
    return 1; // range error
  }

  *size = (size_t) ftell_retval;
  return 0;
}

携帯性

の関係が定義されていないため、 a から alongへの直接変換、size_tおよびその逆の変換は移植性が困難です。かもしれません。LONG_MAXSIZE_MAX<,==, >

代わりに、最初に をテストし< 0、正の場合は に変換しunsigned longます。C は を指定しているLONG_MAX <= ULONG_MAXので、ここでは問題ありません。次に と を比較unsigned longSIZE_MAXます。どちらの型も符号なし型であるため、比較は単純に 2 つのうち幅の広い方に変換されます。ここでも範囲の損失はありません。

于 2019-10-21T21:02:30.093 に答える