#include"apue.h"
int glob=6;
int main(void)
{
int var;
pid_t pid;
int i;
char buf[200];
var=88;
printf("before vfork\n");
if((pid=vfork())<0){
err_sys("vfork error");
}else if(pid==0){
glob++;
var++;
fclose(stdout); //(1)
_exit(0);
}
i = printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
sprintf(buf, "%d\n", i);
write(STDOUT_FILENO, buf, strlen(buf));
exit(0);
}
程序的运行结果如下:
$ ./a.out
before vfork
-1
stdin是标准输入文件,stdout是标准输出文件,stderr标准出错文件,应用在输出的重新定位上。
程序按如下方式使用这些文件:
标准输入是程序可以读取其输入的位置。缺省情况下,进程从键盘读取 stdin。
标准输出是程序写入其输出的位置。缺省情况下,进程将 stdout 写到终端屏幕上。
标准错误是程序写入其错误消息的位置。缺省情况下,进程将 stderr 写到终端屏幕上。
文件描述符:如果我们用fd表示,该fd可以是open、pipe、dup、dup2和creat等调用返回的结果,在linux系统中,设备也是以文件的形式存在,要对该设备进行操作就必须先打开这个文件,打开这个文件就会,就会获得这个文件描述符,它是个很小的正整数,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。文件描述符的优点:兼容POSIX标准,许多Linux和 UNIX系统调用都依赖于它。文件描述符的缺点:不能移植到UNIX以外的系统上去,也不直观。
fd只是一个索引.
文件指针: C语言中使用的是文件指针而不是文件描述符做为I/O的句柄." 文件指针(file pointer)"指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符值.而文件描述符值是文件描述符表中的一个索引.从某种意义上说文件指针就是句柄的句柄。
用下面的流图可以说明问题: (ps: 虽然不是流图关系,但是还是有助于理解)
printf -> stdout -> STDOUT_FILENO(1) -> 终端(tty)
stdout/stdin -- 标准输出输入设备 (printf("..")) 。
stderr -- 标准错误输出设备
两者默认向屏幕输出。
但如果用转向标准输出到磁盘文件,则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕。
printf最后的输出到了终端设备,文件描述符1指向当前的终端可以这么理解:
STDOUT_FILENO = open("/dev/tty", O_RDWR);
stdout/stdin类型为 FILE*
STDOUT_FILENO类型为 int
使用stdout/stdin的函数主要有:fread、fwrite、fclose等,基本上都以f开头
使用STDIN_FILENO的函数有:read、write、close等
fwrite(buf,strlen(buf), 1,stdout);
write(STDOUT_FILENO,&buf,strlen(buf));
总结:注释(1)的fclose 只关闭了stdout,而没有关闭STDOUT_FILENO,所以write() 仍然可以写到STDOUT_FILENO中.
但是把(1)处改为close(STDOUT_FILENO),程序输出变为:
./a.out
before vfork
pid = 28003, glob = 7, var = 89
32
文件描述符和文件流之间的转换 FILE *fdopen(int fildes, const char *type);
这个函数很有用的,功能是将一个流关联到一个打开的文件号filedes上,
该filedes可以是open、pipe、dup、dup2和creat等调用返回的结果
type指定流打开方式,同fopen的打开方式,如"a", "r","w"等等
fdopen的流打开方式服从filedes的打开方式,比如filedes的open指定O_RDONLY,那么fdopen也只能指定"r"的打开方式了。
用fdopen的好处很明显,如果你不得已只能打开文件号,比如socket或者dup调用,但又想用fprintf,fscanf等流操作来进行读写,那么就再fdopen一次好了。
int fileno(FILE stream);
用fileno有什么好处呢?你用fopen打开了文件,但是又想用flock或者lockf来给文件加锁,或者用fcntl来进行某些底层的操作,但上述这些函数只能对打开的文件号操作,而不能对打开流,这时候就用fileno再flock、lockf、fcntl好了。