看过我上一篇文章《深入VC流》的朋友想必对VC流系统的认识有了一定基础,文章的着重点在于流类库的两大基类,关于streambuf类和ios类及其常用的派生类iostream,ostream,iostream从原理和实验两方面已经介绍的差不多了,而对streambuf类的派生类以及文件流类fstream,ifstream,ofstream并没有涉及。这篇文章就是在此基础上使对VC流的认识更上一层楼,着重介绍文件流相关的原理并在此基础上通过反汇编逐渐靠近目标--透视文件句柄分配的原理。
在文章的开始,我还是依照自己的惯例介绍一下在调试时会涉及到内容的基本原理。
一。原理篇
1。filebuf类:streambuf类的派生类,其结构原理可以参见《深入VC流》这里不再赘述。其本质也是系统在配置缓冲区处理的时候划分一块固定的内存区域--保留区域,只不过是属于文件流专用。
先说明一点:既然“保留区域”是由streambuf对象配置的,那么“文件保留区域”就是filebuf对象配置的。总之,清楚“保留区域是由其所对应的对象所配置的”就可以了。在这里强调这一点是因为当我调试进行到尾声的时候才发现自己一直把对象与保留区域混为一谈,例如rdbuf( )函数返回的是对象指针而不是保留区域指针。关于这一点在《深入VC流》中也忽略了。切记!!!
filebuf类也有属于自己的成员变量及相关的函数:
1)。x_fd:文件描述符,用于标识文件保留区域是否于文件绑定;
2)。x_fOpened:
3)。filebuf();构造空的文件保留区域(实际由系统分配)
filebuf( filedesc fd );构造文件保留区域并且绑定到指定的文件
filebuf( filedesc fd, char* pr, int nLength );
构造文件保留区域并与文件绑定,同时初始化保留区域
~filebuf( );析构函数
fd:文件描述符
pr:文件保留区域的指针
nLength:文件保留区域的大小
4)。下面是4个文件保护模式
openprot:default share/prot mode
sh_none: Exclusive mode ― no sharing. sh_read : Read sharing allowed. sh_write : Write sharing allowed.
5)。下面是2个读取文件的模式
binary:二进制模式
text:文本模式
6)。filebuf* attach( filedesc fd );
绑定文件保留区域到由文件描述符指定的文件
7)。filedesc fd()const { return (x_fd==-1)?EOF:x_fd; }
取得文件描述符,若保留区域对象没有与文件绑定则返回EOF,本质就是查看标识x_fd;
8)。int is_open() const { return (x_fd!=-1); }
用于检测文件保留区域是否与文件绑定
9)。filebuf* open( const char* szName, int nMode, int nProt = filebuf::openprot );
打开磁盘文件且绑定文件保留区域
10)。filebuf* close();刷新文件输出缓冲区(继承streambuf特性,保留区域由输入缓冲区和输出缓冲区两部分,但不一定同时存在),关闭打开的文件并且撤消保留区域与文件之间的绑定关系(回收系统资源)。
11)。int setmode( int nMode = filebuf::text );设置读取文件模式
到此filebuf类的成员基本到齐,剩下的是几个需函数,这里就不介绍了。 感觉上这个类的内容很少,你可以任由这种感觉继续,但必须搞清楚几个问题:
1)。保留区域需要绑定到具体的流对象才能正真起作用
2)。filedesc:a typedef equivalent to int
相当于typedef int filedesc;3)。
3)。文件描述是什么,为什么能代表文件?
4)。既然文件描述符能代表文件,它和文件之间必然存在一一对应的关系,这不是文件句柄的特性。那么文件描述符和句柄到底是什么关系,或者它们根本就是一回事?
5)。文件描述符是在哪里被设置即x_fd是在哪里被赋值?观察上面介绍的成员函数只有两种可能性:构造函数和open函数;其它如is_open和fd都只是根据标识x_fd来进行判断并没有改便它的值。
又到了从实验种找答案的时刻,带着这些问题去实验,我相信最终会成功。
2。ifstream,ofstream,fstream有一些同名又同功能的函数:
filebuf* rdbuf() const;返回与当前流对象相关的filebuf buffer object的指针
filedesc fd() const;
void attach( filedesc fd );
int is_open() const;
int setmode( int nMode = filebuf::text );
void open( const char* szName, int nMode, int nProt = filebuf::openprot );
功能与filebuf类的成员函数类同,不再赘述。 二。实验篇
调试环境:VC6.0调试器(也可以结合OD,它的对代码分析模块化的功能可以大大简化代码分析时的工作)
这里听取nbw巴神老哥的建议从反汇编的角度来阐述问题。
4: #include "stdafx.h"
5: #include "fstream.h"
6:
7: int main(int argc, char* argv[])
8: {
00401020 push ebp
00401021 mov ebp,esp
00401023 push 0FFh
00401025 push offset __ehhandler$_main (004163e9)
0040102A mov eax,fs:[00000000]
00401030 push eax
00401031 mov dword ptr fs:[0],esp
00401038 sub esp,84h
0040103E push ebx
0040103F push esi
00401040 push edi
00401041 lea edi,[ebp-90h]
00401047 mov ecx,21h
0040104C mov eax,0CCCCCCCCh
00401051 rep stos dword ptr [edi]
9: ifstream fin;
00401053 push 1
00401055 lea ecx,[ebp-4Ch]
00401058 call ifstream::ifstream (0040c820) //初始化文件流对象,指针为00921D00
0040105D mov dword ptr [ebp-4],0
10: fin.open("test.txt");
00401064 mov eax,[filebuf::openprot (00428fe4)]
00401069 push eax //nProt = filebuf::openprot
0040106A push 1 //nMode=1 ( in )
0040106C push offset string "test.txt" (0042801c) //szName="test.txt"
00401071 lea ecx,[ebp-4Ch]
00401074 call ifstream::open (0040ce60)
11: fin.close();
00401079 lea ecx,[ebp-4Ch]
0040107C call ifstream::close (0040cec0)
12: return 0;
00401081 mov dword ptr [ebp-50h],0
00401088 mov dword ptr [ebp-4],0FFFFFFFFh
0040108F lea ecx,[ebp-4Ch]
00401092 call @ILT+0(ifstream::`vbase destructor') (00401005)
00401097 mov eax,dword ptr [ebp-50h]
13: }
0040109A mov ecx,dword ptr [ebp-0Ch]
0040109D mov dword ptr fs:[0],ecx
004010A4 pop edi
004010A5 pop esi
004010A6 pop ebx
004010A7 add esp,90h
004010AD cmp ebp,esp
004010AF call __chkesp (00401520)
004010B4 mov esp,ebp
004010B6 pop ebp
004010B7 ret
**********************************************************************
//来自00401074 call ifstream::open (0040ce60)的调用 ifstream::open:
0040CE60 push ebp
0040CE61 mov ebp,esp
0040CE63 push ecx
0040CE64 mov dword ptr [ebp-4],ecx
0040CE67 mov ecx,dword ptr [this]
0040CE6A call ifstream::is_open (0040cdd0) //检测文件保留区域是否于文件绑定
0040CE6F test eax,eax //在这个时候还没有绑定
0040CE71 jne ifstream::open+35h (0040ce95) //不跳转,执行绑定
0040CE73 mov eax,dword ptr [prot]
0040CE76 push eax
0040CE77 mov ecx,dword ptr [mode]
0040CE7A or ecx,1
0040CE7D push ecx
0040CE7E mov edx,dword ptr [name]
0040CE81 push edx //open的三个参数入栈
0040CE82 mov ecx,dword ptr [this]
0040CE85 call ifstream::rdbuf (0040cac0) //取得filebuf对象的指针
0040CE8A mov ecx,eax //此处是EAX=00921D00
0040CE8C call filebuf::open (0040e9c0) //打开磁盘文件并且绑定文件保留区域
0040CE91 test eax,eax //返回值是filebuf对象的指针00921D00
0040CE93 jne ifstream::open+58h (0040ceb8) //跳转
0040CE95 mov eax,dword ptr [this]
0040CE98 mov ecx,dword ptr [eax]
0040CE9A mov edx,dword ptr [ecx+4]
0040CE9D mov eax,dword ptr [this]
0040CEA0 mov ecx,dword ptr [eax+edx+8]
0040CEA4 or ecx,2
0040CEA7 push ecx
0040CEA8 mov edx,dword ptr [this]
0040CEAB mov eax,dword ptr [edx]
0040CEAD mov ecx,dword ptr [this]
0040CEB0 add ecx,dword ptr [eax+4]
0040CEB3 call ios::clear (0040cd80)
0040CEB8 mov esp,ebp
0040CEBA pop ebp
0040CEBB ret 0Ch
*************************************************************************
调试到这里,对反汇编代码以及原理篇中所讲述的文件流相关函数有了更清晰的了解,但至于在实验前所提出的问题并没有涉及,甚至连“文件描述符”也没出现。
显然需要对filebuf::open 进行深入的调试,根据原理篇的介绍open函数的功能是“打开磁盘文件且绑定文件保留区域”,同时考虑到第五个问题“文件描述符是在哪里被设置?”此处是用open函数来执行打开函数功能的,因而设置“文件描述符”的位置必定在这个函数中。
这里从逻辑上坚定了调试的信心,经历过漫长调试的朋友都清楚在进入一个函数之前必定要对它的基本功能做一个全局的分析,不论分析的结果如何,但都已经在无意识间把这个函数放到程序这个大局中,而不仅仅局限于代码,这样会事半功倍。
重新调试,来到open函数。
filebuf::open:
0040E9C0 push ebp
0040E9C1 mov ebp,esp
0040E9C3 sub esp,18h
0040E9C6 mov dword ptr [ebp-14h],ecx
0040E9C9 mov eax,dword ptr [this]
0040E9CC cmp dword ptr [eax+30h],0FFh //检测文件是否已经打开
0040E9D0 je filebuf::open+19h (0040e9d9) //跳转
0040E9D2 xor eax,eax
0040E9D4 jmp filebuf::open+256h (0040ec16)
0040E9D9 mov ecx,dword ptr [mode] //ecx=1 ( nMode=in )
0040E9DC and ecx,80h //判断nMode?=binary;
0040E9E2 neg ecx
0040E9E4 sbb ecx,ecx
0040E9E6 and ecx,4000h
0040E9EC add ecx,4000h //状态标志字“stdio”
0040E9F2 mov dword ptr [dos_mode],ecx //保存状态标志字
0040E9F5 mov edx,dword ptr [mode] //edx=1 ( nMode=in )
0040E9F8 and edx,20h //判断nMode?=nocreate
0040E9FB test edx,edx
0040E9FD jne filebuf::open+48h (0040ea08) //不跳转
0040E9FF mov eax,dword ptr [dos_mode] //取出状态标志字“stdio"
0040EA02 or ah,1 //添加状态标志“showpoint"
0040EA05 mov dword ptr [dos_mode],eax //再次存入状态标志“stdio||showpoint" 0040EA08 mov ecx,dword ptr [mode] //ecx=1 ( nMode=in )
0040EA0B and ecx,40h //判断nMode?=replace;
0040EA0E test ecx,ecx
0040EA10 je filebuf::open+5Bh (0040ea1b) //跳转
0040EA12 mov edx,dword ptr [dos_mode]
0040EA15 or dh,4
0040EA18 mov dword ptr [dos_mode],edx
0040EA1B mov eax,dword ptr [mode]
0040EA1E and eax,8 //判断nMode?=app;
0040EA21 test eax,eax
0040EA23 je filebuf::open+77h (0040ea37) //跳转 0040EA25 mov ecx,dword ptr [mode]
0040EA28 or ecx,2
0040EA2B mov dword ptr [mode],ecx
0040EA2E mov edx,dword ptr [dos_mode]
0040EA31 or edx,8
0040EA34 mov dword ptr [dos_mode],edx
0040EA37 mov eax,dword ptr [mode]
0040EA3A and eax,10h //判断nMode?=trunc;
0040EA3D test eax,eax
0040EA3F je filebuf::open+93h (0040ea53) //跳转 0040EA41 mov ecx,dword ptr [mode]
0040EA44 or ecx,2
0040EA47 mov dword ptr [mode],ecx
0040EA4A mov edx,dword ptr [dos_mode]
0040EA4D or dh,2
0040EA50 mov dword ptr [dos_mode],edx
0040EA53 mov eax,dword ptr [mode]
0040EA56 and eax,2 //判断nMode?=out;
0040EA59 test eax,eax
0040EA5B je filebuf::open+0D8h (0040ea98)//跳转
0040EA5D mov ecx,dword ptr [mode]
0040EA60 and ecx,1
0040EA63 test ecx,ecx
0040EA65 je filebuf::open+0B2h (0040ea72)
0040EA67 mov edx,dword ptr [dos_mode]
0040EA6A or edx,2
0040EA6D mov dword ptr [dos_mode],edx
0040EA70 jmp filebuf::open+0BAh (0040ea7a)
0040EA72 mov eax,dword ptr [dos_mode]
0040EA75 or al,1
0040EA77 mov dword ptr [dos_mode],eax
0040EA7A mov ecx,dword ptr [mode]
0040EA7D and ecx,4Dh
0040EA80 test ecx,ecx
0040EA82 jne filebuf::open+0D6h (0040ea96)
0040EA84 mov edx,dword ptr [mode]
0040EA87 or edx,10h
0040EA8A mov dword ptr [mode],edx
0040EA8D mov eax,dword ptr [dos_mode]
0040EA90 or ah,2
0040EA93 mov dword ptr [dos_mode],eax
0040EA96 jmp filebuf::open+0F1h (0040eab1)
0040EA98 mov ecx,dword ptr [mode]
0040EA9B and ecx,1 //判断nMode?=in
0040EA9E test ecx,ecx
0040EAA0 je filebuf::open+0EAh (0040eaaa)
0040EAA2 mov edx,dword ptr [dos_mode]
0040EAA5 mov dword ptr [dos_mode],edx
0040EAA8 jmp filebuf::open+0F1h (0040eab1) //跳转。到此为止对nMode的判断结束,结果为nMode=stdio||showpoint,此时dos_mode=nMode=0x4100;
0040EAAA xor eax,eax
0040EAAC jmp filebuf::open+256h (0040ec16)
0040EAB1 mov dword ptr [smode],40h //_sopen参数之一
0040EAB8 mov eax,[filebuf::sh_read (00428fec)] //sh_read=0xA00
0040EABD or eax,dword ptr [filebuf::sh_write (00428ff0)] //sh_write=0x400;
0040EAC3 or eax,dword ptr [filebuf::sh_none (00428fe8)] //sh_none=0x0;此时eax=1
0040EAC9 mov ecx,dword ptr [share] //ECX=0x1A4;
0040EACC and ecx,eax
0040EACE mov dword ptr [share],ecx //保存保护模式。此时ECX=0;为sh_none
0040EAD1 cmp dword ptr [share],0
0040EAD5 je filebuf::open+170h (0040eb30) //跳转
0040EAD7 mov edx,dword ptr [share]
0040EADA mov dword ptr [ebp-18h],edx
0040EADD cmp dword ptr [ebp-18h],0C00h
0040EAE4 jg filebuf::open+143h (0040eb03)
0040EAE6 cmp dword ptr [ebp-18h],0C00h
0040EAED je filebuf::open+160h (0040eb20)
0040EAEF cmp dword ptr [ebp-18h],800h
0040EAF6 je filebuf::open+14Eh (0040eb0e)
0040EAF8 cmp dword ptr [ebp-18h],0A00h
0040EAFF je filebuf::open+157h (0040eb17)
0040EB01 jmp filebuf::open+170h (0040eb30)
0040EB03 cmp dword ptr [ebp-18h],0E00h
0040EB0A je filebuf::open+169h (0040eb29)
0040EB0C jmp filebuf::open+170h (0040eb30)
0040EB0E mov dword ptr [smode],10h
0040EB15 jmp filebuf::open+170h (0040eb30)
0040EB17 mov dword ptr [smode],20h
0040EB1E jmp filebuf::open+170h (0040eb30)
0040EB20 mov dword ptr [smode],30h
0040EB27 jmp filebuf::open+170h (0040eb30)
0040EB29 mov dword ptr [smode],40h
0040EB30 push 180h
0040EB35 mov eax,dword ptr [smode]
0040EB38 push eax //shflag
0040EB39 mov ecx,dword ptr [dos_mode]
0040EB3C push ecx //oflag
0040EB3D mov edx,dword ptr [name]
0040EB40 push edx //Filename
0040EB41 call _sopen (00410ae0) //返回值3
---------------------------------------------------------------------------------------------------------------
int _sopen( const char *filename, int oflag, int shflag [, int pmode ] );
filename:Filename
oflag:Type of operations allowed
shflag:Type of sharing allowed
pmode:Permission setting
在此考虑到三点:
1。“文件描述符”是在打开文件时产生的。
2。_sopen( )的作用是用来得到文件id。
3。根据原理篇可以知道open函数有两个功能,打开文件和绑定文件保留区域。显然到这里为止完成了打开文件这个功能.
根据这三点作出推测:"文件id"就是“文件描述符”.
-------------------------------------------------------------------------------------------------------------
0040EB46 add esp,10h
0040EB49 mov ecx,dword ptr [this] //取得filebuf对象指针(即此时的流对象指针)
0040EB4C mov dword ptr [ecx+30h],eax //文件id存入偏移流对象指针0X30处
0040EB4F mov edx,dword ptr [this]
0040EB52 cmp dword ptr [edx+30h],0FFh //判断文件id是否成功
0040EB56 jne filebuf::open+19Fh (0040eb5f) //此时成功,跳转
0040EB58 xor eax,eax
0040EB5A jmp filebuf::open+256h (0040ec16)
0040EB5F mov ecx,dword ptr [this]
0040EB62 call streambuf::lock (0040d0c0) //?
0040EB67 mov eax,dword ptr [this]
0040EB6A mov dword ptr [eax+34h],1 //偏移流对象头指针0X34代表什么?
0040EB71 mov ecx,dword ptr [this]
0040EB74 call streambuf::unbuffered (0040d320) //返回filebuf对象的缓冲性质
0040EB79 test eax,eax //返回值EAX=0,表明为缓冲的
0040EB7B jne filebuf::open+215h (0040ebd5) //不跳转
0040EB7D mov ecx,dword ptr [this]
0040EB80 call streambuf::ebuf (0040d290) //返回保留区域的尾指针
0040EB85 test eax,eax //返回EAX=0;表明保留区域还不存在
0040EB87 jne filebuf::open+215h (0040ebd5) //不跳转
0040EB89 push 0A6h
0040EB8E push offset string "filebuf1.cpp" (0042906c)
0040EB93 push 2
0040EB95 push 200h //保留区域的固定长度
0040EB9A call operator new (004101a0) //?doallocate?
------------------------------------------------------------------------------------------------------------
这个函数让我产生不小的疑惑:当执行完这个函数后的下一个函数是setb函数是用来绑定保留区域的,但到这里为止从上面的ebuf函数来看保留区域还没有分配,所以这个函数的功能必定是分配保留区域。但对于这个函数我只见过在用VC编程时来动态分配存储空间,想不到会出现在汇编代码中;还有一点就是保留区域的分配是通过doallocate函数来实现的,但这里却......
--------------------------------------------------------------------------------------------------------------
0040EB9F add esp,10h
0040EBA2 mov dword ptr [ebp-10h],eax //返回值EAX=00921AD0,为保留区域指针
0040EBA5 mov ecx,dword ptr [ebp-10h]
0040EBA8 mov dword ptr [sbuf],ecx //把保留区域指针存入sbuf
0040EBAB cmp dword ptr [sbuf],0 //判断保留区域是否成功分配
0040EBAF jne filebuf::open+1FDh (0040ebbd) //跳转
0040EBB1 push 1 //标志保留区域为无缓冲的
0040EBB3 mov ecx,dword ptr [this]
0040EBB6 call streambuf::unbuffered (0040d850) //设置保留区域的缓冲性质0040EBBB jmp filebuf::open+215h (0040ebd5)
0040EBBD push 1 //nDelete=1;
0040EBBF mov edx,dword ptr [sbuf]
0040EBC2 add edx,200h
0040EBC8 push edx //peb:保留区域尾地址。此时EDX=00921CD0
0040EBC9 mov eax,dword ptr [sbuf]
0040EBCC push eax //pb:保留区域首地址。此时EAX=00921AD0
0040EBCD mov ecx,dword ptr [this]
0040EBD0 call streambuf::setb (0040f170)
//void setb( char* pb, char* peb, int nDelete = 0 );
此函数在这里的作用:设置保留区域的指针,并且把保留区域绑定到
If nDelete is not 0, the reserve area will be deleted when: (1) the base pointer is changed by another setb call, or (2) the streambuf destructor is called. 0040EBD5 mov ecx,dword ptr [mode] //mode=1; "in"
0040EBD8 and ecx,4 //检测是否为“ate”模式
0040EBDB test ecx,ecx
0040EBDD je filebuf::open+24Bh (0040ec0b) //跳转
0040EBDF mov edx,dword ptr [mode] //这一部分代码用来回收系统资源并设置返回值为0,标志失败
0040EBE2 push edx
0040EBE3 push 2
0040EBE5 push 0
0040EBE7 mov eax,dword ptr [this]
0040EBEA mov edx,dword ptr [eax]
0040EBEC mov ecx,dword ptr [this]
0040EBEF call dword ptr [edx+0Ch]
0040EBF2 cmp eax,0FFh
0040EBF5 jne filebuf::open+24Bh (0040ec0b)
0040EBF7 mov ecx,dword ptr [this]
0040EBFA call filebuf::close (0040d0d0) //回收系统资源,包括刷新输出缓冲区、关闭打开的文件、撤消文件与保留区域的绑定
0040EBFF mov ecx,dword ptr [this]
0040EC02 call streambuf::unlock (0040d140)
0040EC07 xor eax,eax //返回值为0
0040EC09 jmp filebuf::open+256h (0040ec16)
0040EC0B mov ecx,dword ptr [this]
0040EC0E call streambuf::unlock (0040d140) //?
0040EC13 mov eax,dword ptr [this] //保存filebuf对象指针到EAX用于函数返回。
0040EC16 mov esp,ebp
0040EC18 pop ebp
0040EC19 ret 0Ch
****************************************************************************
到这里,此次的调试之旅已经结束。
下面就这次实验做一下总结:
同上次一样,这次实验选取的对象也是一个简短的程序。
#include "stdafx.h"
#include "fstream.h"
int main(int argc, char* argv[])
{
ifstream fin;
fin.open("test.txt");
fin.close();
return 0;
}
注意:下面的代码只是反汇编代码的流程表达,根本不是程序。
1。显然这次实验的一切价值都蕴涵在open函数中。ifstream::open
{
if ( !ifstream::is_open( ) )
{
ECX=EAX=ifstream::rdbuf( ) ;
EAX=filebuf::open ( name, mode, prot ) ;
}
else
{
ios::clear () ;
}
return ;
}
2。在《深入VC流》中已经提到关于流的任何实际操作都是通过streambuf类对象对保留区域的操作来完成。在这里由于是文件流,所以最基层的操作都是filebuf::open函数中完成。其中调用streambuf类的程序函数只不过是通过类继承接替功能,本质任是在filebuf类的作用区域内。
typedef 保留区域指针 *pFileBuffer ;
typedef filebuf类对象指针 *filebuf ;
filebuf::open
{
if( *( filebuf + 0x30 ) != 0xFF )
return false;
dos_mode = nMode = { 一系列的基本运算和逻辑运算 } ;
share = { 一系列的基本运算和逻辑运算 } ;
smode = 0x40 ;
EAX=_sopen ( name, dos_mode, smode ) ;
*( filebuf + 0x30 ) = EAX ;
if ( *( filebuf + 0x30 ) == 0xFF ) //如果文件已经打开
return false;
*( filebuf + 0x34 ) = 0x1 ;
if ( !streambuf::unbuffered( ) && !streambuf::ebuf( ) )
{ //若filebuf对象是缓冲的且保留区域尚未分配的
//分配保留区域
pFileBuffer = EAX = operator new ( 0x200, 2, "filebuf1.cpp", 0x0A6 ) ;
if ( pFileBuffer == 0 ) //若保留区域分配失败
streambuf::unbuffered ( 1 ) ; //改变保留区域性质为无缓冲
else //若分配保留区域
streambuf::ebuf ( pFileBuffer, pFileBuffer+0x200, 1 ) ; //绑定
if ( mode != ate )
return true;
else
return false;
}
} 3。到这里对程序的流程应该清楚了,还有一点需要总结的是调试过程中出现的几个关键数据:
*filebuf ――0X00921D00 *pFileBuffer――0X00921AD0
*( filebuf + 0x30 ) = FILE_ID
*( filebuf + 0x34 ) = 0x1 未知(那位朋友知道的话,告知一声,感激不尽!)
4。调试过程中一些未被执行的代码并没有详细的分析,但如果理解那些经过分析的代码的话,也就很容易理解了。
5。经过这次实验对文件id和文件描述符有了一定的理解,文件描述符的标志x_fd显然是在_sopen()函数中被设置的。如果还要深入那就得分析_sopen()函数了,若能力所及我会在下一篇中给予分析。
6。有一点遗憾的是到此为止还没出现文件句柄,但也有欣慰关于句柄周围的一些概念例如流对象、保留区域、文件id、文件描述等已基本搞清楚,这是不是更让我们共同期待句柄的透视?
参考资料:MSDN;fstream.h
为了降低各位阅读代码时眼睛的疲劳度,提供超星阅览器的编辑的电子版供下载附件:DeepIntoFileStream.rar
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!