1

次のように read() を呼び出してファイルを読み取った場合:

unsigned char buf[512];
memset(buf, 0, sizeof(unsigned char) * 512);
int fd;
int readcount;
int offset = 10315001; /* file size is 14315504 */

fd = open("myfile", O_RDONLY);
lseek(fd, offset, SEEK_SET);
readcount = read(fd, (void*)buf, 8);
close(fd);

read() は 0 を返しますが、"buf" のメモリは変更されています (もう 0 ではありません)。そして、次のように fread() で同じオフセットと同じファイルを読み取ろうとした場合:

FILE* file;
file = fopen("myfile", "r");
fseek(file, offset, SEEK_SET);
readcount = fread((void*)buf, 8, 1, file);
fclose(file);

fread() も 0 を返しますが、buf は以前と同じです。

read() が失敗した場合、「buf」のメモリ空間を変更するのはなぜですか? それとも私はいくつかの間違いを犯しましたか?

手伝ってくれてありがとう : )

編集: 上記のコードを実行するたびに、「buf」は read() によって同じように変更されました-> 0 から同じ値に。したがって、変更された「buf」はランダムな値ではない可能性がありますか?

編集2:オフセットパラメータは有効です(twalbergに感謝します)。別の有効なオフセットを読み取ると、read()とfread()の両方が成功し、「b​​uf」の結果は同じになります。read() が失敗したときに何が問題なのかを見つける方法はありますか? read() が 0 を返した場合、errno は「エラーなし」です。

4

2 に答える 2

2

read()への呼び出しが失敗した後、またはゼロバイトが成功した後のバッファーの内容read()は未定義です。

発生した可能性が高いのは、一時ストレージ (別のガベージでいっぱいになった) に内部 (おそらくカーネル側) バッファーを割り当て、バッファーをバッファーにコピーしましたが、実際にはそのバッファーに書き込みませんでした。

読み取りが成功した後にのみバッファを調べる必要があるため、これは問題になりません。そのバッファに重要なデータがある場合は、そのデータを消去する可能性のある関数に渡す前に、そこから移動してください!

編集:コードは次のようになります。想像してみてくださいkernel_read()ファイル記述子から読み取るシステムコールであり、プロセスのアドレス空間ではなくカーネルのアドレス空間に割り当てられたバッファーを使用します (カーネルは一見奇妙なことを行うため)。

extern __kernel void *kernel_malloc(size_t size);
extern void kernel_copy_from_kernel_to_userland(void *dest, __kernel void *src, size_t size);
extern void kernel_free(__kernel void *address);

extern int kernel_is_valid_fd(int fd);
extern ssize_t kernel_read(int fd, __kernel void *kbuf, size_t count);

ssize_t read(int fd, void *buf, size_t count) {
    ssize_t result = -1;

    if (0 == kernel_is_valid_fd(fd)) {
        __kernel void *kernelbuf = kernel_malloc(count);
        if (kernelbuf) {
            result = kernel_read(fd, kernelbuf, count);
            kernel_copy_from_kernel_to_userland(buf, kernelbuf, count);
            kernel_free(kernelbuf);
        } else {
            errno = ENOMEM;
        }
    } else {
        errno = EINVAL;
    }

    return result;
}

これは思考実験であり、出荷されているオペレーティング システムからの実際の実装ではありませんが、見たものを見た理由を理解するのに役立つかもしれません。

于 2012-06-29T12:29:21.023 に答える
1

ここで何が起こっているのかがわかったと思います。ファイルはバイナリファイルですが、テキストモード (O_RDONLY) で read() します。

オフセット 10315001 の値は 0x1a です。read() および fread() 関数がテキスト モードで 0x1a に一致する場合、どちらも 0 を返しますが、違いは、read() は引き続きバイナリ モードで buf を書き込みますが、fread( )これはしません。

于 2012-07-02T06:22:38.077 に答える