none
freadの読み取りサイズ指定が2段である理由 RRS feed

  • 質問

  • こんにちは。

     

    昔から少し疑問に思っていることがあるのですが、

    freadの引数で読み取り量の指定が、

    size_t fread( 
       void *buffer,
       size_t size,   <-----項目あたりのサイズ
       size_t count,  <-----項目数
       FILE *stream 
    );
    と、size,countの2段になっているのには深い理由があるのでしょうか?


    結局のところ、読み取りサイズはsize*count [bytes]だと思うので、sizeとcountを入れ替えても
    同じだし、だったら2つの引数を統合してバイトサイズ指定の引数にすればいいじゃない?
    と思ってしまいます。
    freadの戻り値が、sizeとcountの値を入れ替えた場合で変わる(MSDNのヘルプによれば
    fread は、実際に読み取った完全な項目の数を返します。」であるから)のはわかった
    のですが、それだけとは思えず、もっと何か(2つ入れ替えた場合の)「違い」がありそうな...。
    size,countの2つの引数を持っている理由や、入れ替えた場合の挙動の違いについて
    ご教授いただければ幸いです。
    2009年1月6日 8:48

回答

  • fread は、実際に読み取った完全な項目の数を返します。」

    ですから、たとえば、

    sizeof(int)*10 + sizeof(char)*3

    のようなデータがある場合、

    char inbuf[256];
    fread(inbuf, sizeof(int), 20, fp);

    とすると戻り値が 10 に、

    char inbuf[256];
    fread(inbuf, sizeof(char), 20, fp);

    とすると戻り値が 20になります。

    つまり「項目あたりのサイズ」単位でデータを取り出すということになります。
    これは明らかに
    結局のところ、読み取りサイズはsize*count [bytes]だと思うので、sizeとcountを入れ替えても
    同じだし、だったら2つの引数を統合してバイトサイズ指定の引数にすればいいじゃない?
    と思ってしまいます。
    ではないでしょう。
    2009年1月7日 1:27

すべての返信

  • #正確なところは知りません。

    freadはC言語の仕様に定められた標準関数です。
    そしてC言語が登場したのは30年近く前です。
    その当時のハードウェアでは大きすぎるサイズを指定するとメモリに入りきらなくてエラーになるとか、そんな状況があったのではないでしょうか。
    対策としてソフト側で一度に読み込むサイズをハードに応じて指定するようにしたとか。
    あくまで想像ですけどね。

    今のWindowsでは入れ替えても違いはないと思います。
    実際にハードから読み取りを行ったサイズは、ここで指定したサイズで読まれる訳ではなく、いろいろな階層にキャッシュされるので実際のサイズを調べるのは難しいです。(どこかのキャッシュから読んだり、キャッシュに乗せるためにもっと大きなサイズで読み込んだり)
    2009年1月6日 10:00
  • 私も正確な所は知りませんが、

     

    至極素直に利用者側の簡便の為と理解していました。

    確かに結果的には同じ事になるのでしょうけれど、

    サイズこれこれの固定長レコードを何レコード分と言う方が認識しやすいと言う話ではないかと思っています。

    固定長レコードで考えるとレコードサイズは固定で良いわけでレコード数だけを変えれば読み込みの数を変更できます。

     

    そういう意味では、

     

    > freadの戻り値が、sizeとcountの値を入れ替えた場合で変わる(MSDNのヘルプによれば
    > 「fread は、実際に読み取った完全な項目の数を返します。」であるから)のはわかった
    > のですが、それだけとは思えず、もっと何か(2つ入れ替えた場合の)「違い」がありそうな...。

     

    に関してはそれだけなんじゃないかと思います。

     

    2009年1月7日 1:01
  • fread は、実際に読み取った完全な項目の数を返します。」

    ですから、たとえば、

    sizeof(int)*10 + sizeof(char)*3

    のようなデータがある場合、

    char inbuf[256];
    fread(inbuf, sizeof(int), 20, fp);

    とすると戻り値が 10 に、

    char inbuf[256];
    fread(inbuf, sizeof(char), 20, fp);

    とすると戻り値が 20になります。

    つまり「項目あたりのサイズ」単位でデータを取り出すということになります。
    これは明らかに
    結局のところ、読み取りサイズはsize*count [bytes]だと思うので、sizeとcountを入れ替えても
    同じだし、だったら2つの引数を統合してバイトサイズ指定の引数にすればいいじゃない?
    と思ってしまいます。
    ではないでしょう。
    2009年1月7日 1:27