3

私は C の初心者で、 を使用しようとしていますdup()。この関数をテストするプログラムを作成しました。結果は、期待したものとは少し異なります。

コード:

// unistd.h, dup() test

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

extern void dup_test();

int main() {
    dup_test();
}

// dup()test
void dup_test() {
    // open a file
    FILE *f = fopen("/tmp/a.txt", "w+");
    int fd = fileno(f);
    printf("original file descriptor:\t%d\n",fd);

    // duplicate file descriptor of an opened file,
    int fd_dup = dup(fd);
    printf("duplicated file descriptor:\t%d\n",fd_dup);
    FILE *f_dup = fdopen(fd_dup, "w+");

    // write to file, use the duplicated file descriptor,
    fputs("hello\n", f_dup);
    fflush(f_dup);
    // close duplicated file descriptor,
    fclose(f_dup);
    close(fd_dup);

    // allocate memory
    int maxSize = 1024; // 1 kb
    char *buf = malloc(maxSize);

    // move to beginning of file,
    rewind(f);
    // read from file, use the original file descriptor,
    fgets(buf, maxSize, f);
    printf("%s", buf);

    // close original file descriptor,
    fclose(f);

    // free memory
    free(buf);
}

プログラムは、複製された fd を介して書き込みを試み、複製された fd を閉じてから、元の fd を介して読み取りを試みます。

複製された fd を閉じると、io キャッシュが自動的にフラッシュされると予想していましたが、そうではありません。fflush()コード内の関数を削除すると、元の fd は複製された fd によって書き込まれたコンテンツを読み取ることができなくなります。すでに閉鎖されています。

私の質問は:

これは、複製された fd を閉じると、自動的にフラッシュされないということですか?


@編集:

申し訳ありませんが、私の間違いです。理由が見つかりました。最初のプログラムでは次のようになっています。

close(fd_dup);

しかし、持っていません:

fclose(f_dup);

使用後はfclose(f_dup);交換close(f_dup);して動作します。

したがって、複製された fd は、適切な方法で閉じると自動的にフラッシュされます。 write()&close()はペアであり、fwrite()&fclose()はペアであり、それらを混在させるべきではありません。

実際、コードでは、複製された fd_dup をwrite()&close()で直接使用することができ、新しいものを作成する必要はまったくありませんFILE

したがって、コードは次のようになります。

// unistd.h, dup() test

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 1024 // 1 kb

extern void dup_test();

int main() {
    dup_test();
}

// dup()test
void dup_test() {
    // open a file
    FILE *f = fopen("/tmp/a.txt", "w+");
    int fd = fileno(f);
    printf("original file descriptor:\t%d\n",fd);

    // duplicate file descriptor of an opened file,
    int fd_dup = dup(fd);
    printf("duplicated file descriptor:\t%d\n",fd_dup);

    // write to file, use the duplicated file descriptor,
    write(fd_dup, "hello\n", BUF_SIZE);
    // close duplicated file descriptor,
    close(fd_dup);

    // allocate memory
    char *buf = malloc(BUF_SIZE);

    // move to beginning of file,
    rewind(f);
    // read from file, use the original file descriptor,
    fgets(buf, BUF_SIZE, f);
    printf("%s", buf);

    // close original file descriptor,
    fclose(f);

    // free memory
    free(buf);
}
4

2 に答える 2

2

dupマニュアルページから:

これらのシステム コールの 1 つから正常に戻った後、古いファイル記述子と新しいファイル記述子が交換可能に使用される場合があります。これらは同じオープン ファイルの説明 (open(2) を参照) を参照するため、ファイル オフセットとファイル ステータス フラグを共有します。たとえば、記述子の 1 つで lseek(2) を使用してファイル オフセットを変更すると、もう一方のオフセットも変更されます。

これは、複製されたファイル記述子に書き込むときにシーク ポインターが変更されることを意味するため、複製に書き込んだ後に最初のファイル記述子から読み取っても、データは読み取られません。

fdopen複製されたストリームの別々の seek_ptr と end_ptr を作成するために使用しています。これにより、複製fd_dupが停止します。そのため、ストリームをフラッシュして閉じた後にデータを読み取ることができます。

2 番目のファイル記述子をフラッシュしないと読み取れない理由について、有力な事実を見つけることができませんでした。syncシステムコールに関連している可能性があることを付け加えることができます。

結局、IO バッファが必要な場合は、間違ったメカニズムを使用している可能性があります。名前付きパイプやその他のバッファリング OS メカニズムを確認してください。

于 2014-11-03T13:54:35.663 に答える