2016-10-12 8 views
0

次の例では、デフォルトのファイル番号stderrを閉じて、fdopen()を介してテンポラリファイルの2というテキストファイルをテンポラリファイルディスクリプタからdup()に再オープンします。次に、我々はこの記述子に直接write()2。これはファイル上の最初の書き込み操作であり、したがって空のバッファを持っているので、安全に行うことができます。この後、stderrfprintf()を追加します。次に、stderrを閉じます(したがって、関連する記述子2は自動的に閉じます)。元の記述子fdは有効なままです。それを介して、一時ファイルの先頭に移動し、内容を読み込んで標準出力に出力します。しかし、出力が文字化けしている:lseek()を使用すると、ファイル記述子のread()が失敗するのはなぜですか?

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

int main(void) 
{ 
    int fd; 
    char buf[200]; 
    int n; 
    char fname[] = "/tmp/tst-perror.XXXXXX"; 
    fd = mkstemp (fname); 
    fclose (stderr); 
    dup2 (fd, 2); 
    stderr = fdopen (2, "w"); 
    fd = fileno(stderr); 
    char *s = "this is a test\n"; 
    n = write(fd, s, strlen(s)); 
    fprintf(stderr, "multibyte string\n"); 
    fclose (stderr); 
// close(fd); 
// fd = open(fname, O_RDONLY); 
    lseek (fd, 0, SEEK_SET); 
    n = read (fd, buf, sizeof (buf)); 
    printf("%.*s", (int) n, buf); 
    close (fd); 
    return 0; 
} 

出力は次のようになります。

$ ./a.out 
���� 

私たちは、「クローズ」と「オープン」行のコメントを解除し、「のlseek」行をコメントした場合、予想通り、出力は次のとおりです。

$ ./a.out 
this is a test 
multibyte string 

write() はバッファを持っていない、とstderrたちは近くないトンをすれば、出力が文字化けしているなぜ、 それが閉じている書かれ、オフになっています彼はそれを読む前にファイル?

+1

また、あなたが 'lseek'のストリームを注意してください。 'man 2 lseek'の注釈を見てください。*いくつかのデバイスはシークできず、POSIXはlseek()をサポートしなければならないデバイスを指定していません。 –

答えて

1

関数からの戻り値のチェックはありません。もしそこにいたら、あなたはそのエラーを見つけたでしょう。最後の呼び出し以降の呼び出しfd

fd = fileno(stderr);  // getting the fd from current stderr 
    fclose (stderr);   // closing stderr 
    ... 
    lseek (fd, 0, SEEK_SET); // seeking on fd which was already closed 

が実際に定義されていない(というかそれが閉じられたファイルディスクリプタ参照):

とにかく、問題があります。したがって、fdでの操作は、EBADF(有効なファイル記述子ではありません)に失敗します。

fd = open(...)を再度含めると、fdが有効になり、コードが有効になることは明らかです。

+0

実際、私の本来の目的は、 "fileno"と "write"行に "fd2"を使うことでした。今はすべてが動作します。 –

関連する問題