Perché chiudere () la chiamata di sistema che scarica l'output?
Domanda
Ecco il mio codice:
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
int main(int argc,char *argv[])
{
int oldfd;
int newfd;
if(argc!=2)
{
printf("Usgae : %s file_name\n",argv[0]);
exit(0);
}
oldfd=open(argv[1],O_RDWR|O_APPEND,S_IRWXU); // Opening the file in Read/Write mode
if (-1 == oldfd)
{
perror("Error opening file");
exit(0);
}
close(1); // closing stdout
newfd=dup(oldfd); //Now this newfd holds the value 1
close(oldfd); //closing the oldfd
printf("\nStack Overflow"); //Now this printf will print content into the file as stdout closed already
close(newfd);// closing newfd
return 0;
}
Quello che sto effettivamente cercando di fare è semplicemente stampare "stack overflow" al file usando printf () invece di scrivere () chiamata di sistema.
Non sta stampando il contenuto nel file. Ma una cosa che ho osservato è che se rimuovo il codice:
close(newfd)
Sta stampando il contenuto nel file come previsto. Ma non riesco a capire perché. Ho stampato il contenuto e poi solo sto chiudendo il Newfd.
Qual è il motivo per questo?
Soluzione
Quello che sta realmente accadendo qui è quello printf
L'output è bufferita e non inviata immediatamente a FD 1; Invece il buffer viene scaricato nel descrittore di file 1 dal tempo di esecuzione C dopo il ritorno da main
. Se tu close(newfd)
, hai effettivamente ostruito il flusso automatico che viene altrimenti eseguito dal tempo di esecuzione all'uscita.
Se esplicitamente fflush(stdout)
prima di te close(newfd)
, il tuo output dovrebbe apparire nel file.
A proposito, se si desidera reindirizzare un descrittore di file specifico, esiste una chiamata di sistema alternativa dup2(oldfd, 1)
che rende FD 1 un duplicato di oldfd
, chiudendo FD 1 se era precedentemente aperto.
Altri suggerimenti
Quando usi direttamente i descrittori di file, lo vorrai evitare usando le funzioni C stdio come printf
. Cambiare il descrittore di file sottostante da sotto lo strato STDIO sembra irto di pericolo.
Se cambi il tuo printf
a quanto segue:
write(newfd, "\nStack Overflow", 15);
allora probabilmente otterrai l'output che ti aspetti (se il tuo close(newfd)
o no).
close
, write
, open
sono chiamate di sistema Per lo più fatto all'interno del Kernel Linux; Quindi dal punto di vista dell'applicazione, sono operazioni atomiche elementari.
printf
e fprintf
sono funzioni di libreria standard costruite sopra questi (e altri) Syscalls.
Prima Uscita-ing (ad esempio il ritorno da main
), la libreria e l'ambiente standard (in particolare il codice in crt*.o
chiamando il tuo main
) sta eseguendo le funzioni registrate da atexit; e l'I/O standard è (una specie di) che registra una chiamata a fflush Al momento di uscita. Così la stdout
è fflush
-Ed al tempo di uscita. Se tu close
Il suo descrittore in main, che il flush non fallisce e non fa nulla.
Penso che non dovresti mescolare stdio
e crudo write
-S allo stesso descrittore di scrittura. Prendi in considerazione l'uso fdopen
o freopen