15

これが私の問題の説明です:

Cのシステムコールを使って6.3GB程度の大きなファイルを全てメモリに読み込みたいのですreadが、エラーが発生します。コードは次のとおりです。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>

int main(int argc, char* argv[]) {
    int _fd = open(argv[1], O_RDONLY, (mode_t) 0400);
    if (_fd == -1)
        return 1;
    off_t size = lseek(_fd, 0, SEEK_END);
    printf("total size: %lld\n", size);
    lseek(_fd, 0, SEEK_SET);
    char *buffer = malloc(size);
    assert(buffer);
    off_t total = 0;
    ssize_t ret = read(_fd, buffer, size);
    if (ret != size) {
        printf("read fail, %lld, reason:%s\n", ret, strerror(errno));
        printf("int max: %d\n", INT_MAX);
    }
}

そしてそれをコンパイルします:

gcc read_test.c

次に実行します:

./a.out bigfile

出力:

total size: 6685526352
read fail, 2147479552, reason:Success
int max: 2147483647

システム環境は

 3.10.0_1-0-0-8 #1 SMP Thu Oct 29 13:04:32 CST 2015 x86_64 x86_64 x86_64 GNU/Linux

私が理解していない2つの場所があります:

  1. 大きなファイルの読み取りは失敗しますが、小さなファイルでは失敗しません。
  2. エラーが出ていてもerrnoが正しく設定されていないようです。
4

4 に答える 4

15

システム コールはread、複数の理由で要求されたサイズよりも小さい数を返す場合があります。ゼロ以外の正の戻り値はエラーでerrnoはなく、この場合は設定されず、その値は不確定です。ファイルの終わりまたはエラーがread返されるまで、ループで読み取りを続ける必要があります。通常のファイルからでも、1 回の呼び出しで完全なブロックを読み取るために依存するのは、非常に一般的なバグです。より単純なセマンティクスに使用します。0-1readfread

の値を出力しますがINT_MAX、これは問題とは関係ありません。off_tとのサイズがsize_t面白いものです。あなたのプラットフォームである 64 ビット GNU/Linux では、 と の両方が 64 ビット長であることは幸運off_tですsize_t。 定義ssize_tと同じサイズです。size_t他の 64 ビット プラットフォームでは、off_tが よりも小さい場合がsize_tあり、ファイル サイズを正しく評価size_tできないか、 よりもoff_t小さいmalloc場合があり、ファイル サイズよりも小さいブロックが割り当てられます。この場合、両方の呼び出しでサイレントに切り捨てられるreadため、同じ小さいサイズが渡されることに注意してください。size

于 2016-07-16T08:16:09.233 に答える