您的位置:首页 > 运维架构

glibc-2.15 : fopen 源码

2015-10-27 16:49 309 查看


0. 使用cscope查找fopen定义 (推荐)

$ cd glibc-2.15
$ cscope -R
注: cscope的使用请移步这里

一些快捷键 :

    ctrl + ]   : 查找定义

    ctrl + t   : 返回上一个位置

1. 使用grep找到fopen的定义(效率低)

这里使用grep命令查找。

直觉告诉我,可以通过查找函数原型找到fopen的定义,于是,我输入了如下的命令。

(其实可以先简单的用grep查找,碰碰运气,如果输出结果不多,可以直接定位;如果结果太多了,就考虑使用正则表达式匹配了。或者会用ctags、cscope的同学请忽略这篇文章)

$ grep -E "int\W*fseek\W*\(FILE" * -r
conform/data/stdio.h-data:function int fseek (FILE*, long int, int)
libio/stdio.h:extern int fseek (FILE *__stream, long int __off, int __whence);
manual/stdio.texi:@deftypefun int fseek (FILE *@var{stream}, long int @var{offset}, int @var{whence})


虽然使用grep得到了一些结果,但是都不是fopen的定义。
这是因为,glibc中的函数,一般通过宏进行定义。我们修改grep命令,再次查找。

$ grep -E "#\W*define\W*fopen\W*" * -r
hurd/fopenport.c:#define fopencookie _IO_fopencookie
include/stdio.h:#   define fopen(fname, mode) _IO_new_fopen (fname, mode)
libio/stdio.h:#  define fopen fopen64


(⊙o⊙),看到第二行了吗,确实是个宏定义。(第三行的结果,我没有弄懂,请大家赐教)

需要继续查找 _IO_new_fopen 的定义

$ grep -E "_IO_new_fopen" * -r
ChangeLog.11:	* libio/iofopen.c (_IO_new_fopen): Likewise.
ChangeLog.13:	(__fopen_internal): New function.  Split out from _IO_new_fopen.
ChangeLog.13:	(_IO_new_fopen): Call __fopen_internal.
ChangeLog.15:	_IO_old_fopen, _IO_new_fopen, _IO_fopen64, __fopen_internal,
include/stdio.h:extern _IO_FILE *_IO_new_fopen (const char*, const char*);
include/stdio.h:#   define fopen(fname, mode) _IO_new_fopen (fname, mode)
libio/iofopen.c:# define _IO_new_fopen fopen
libio/iofopen.c:_IO_new_fopen (filename, mode)
libio/iofopen.c:strong_alias (_IO_new_fopen, __new_fopen)
libio/iofopen.c:versioned_symbol (libc, _IO_new_fopen, _IO_fopen, GLIBC_2_1);
libio/iolibio.h:extern _IO_FILE *_IO_new_fopen (const char*, const char*);
sysdeps/wordsize-64/iofopen.c:weak_alias (_IO_new_fopen, _IO_fopen64)
sysdeps/wordsize-64/iofopen.c:weak_alias (_IO_new_fopen, fopen64)


_IO_new_fopen的定义就在 libio/iofopen.c 中

_IO_FILE *
_IO_new_fopen (filename, mode)
const char *filename;
const char *mode;
{
return __fopen_internal (filename, mode, 1);
}


继续查找__fopen_internal , 也在 libio/iofopen.c 中

_IO_FILE *
__fopen_internal (filename, mode, is32)
const char *filename;
const char *mode;
int is32;
{
struct locked_FILE
{
struct _IO_FILE_plus fp;
#ifdef _IO_MTSAFE_IO
_IO_lock_t lock;
#endif
struct _IO_wide_data wd;
} *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));

if (new_f == NULL)
return NULL;
#ifdef _IO_MTSAFE_IO
new_f->fp.file._lock = &new_f->lock;
#endif
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
_IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps);
#else
_IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL);
#endif
_IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
INTUSE(_IO_file_init) (&new_f->fp);
#if  !_IO_UNIFIED_JUMPTABLES
new_f->fp.vtable = NULL;
#endif
if (INTUSE(_IO_file_fopen) ((_IO_FILE *) new_f, filename, mode, is32)
!= NULL)
return __fopen_maybe_mmap (&new_f->fp.file);

INTUSE(_IO_un_link) (&new_f->fp);
free (new_f);
return NULL;
}


2.源码分析

TODO

* 一些注释

grep 加上-E是使用 ”扩展的正则表达式“, 需要学习的请移步这里

其实,写成下面的形式也是可以的,但是如果某的返回值和和函数名字之间不只有一个空格时,会找不到函数原型的。

grep "int fseek (FILE" * -r


* Linux 的fopen 与 windows的fopen 之间的区别

linux下查看fopen的manpage,得知,fopen的第二个参数mode有一些需要注意的地方,先看原文:

The  mode  string  can  also include the letter 'b' either as a last character or as a character between the characters in any of the two-character strings
described above.  This is strictly for compatibility with C89 and has no effect; the 'b' is ignored on  all  POSIX  conforming  systems,  including  Linux.
(Other systems may treat text files and binary files differently, and adding the 'b' may be a good idea if you do I/O to a binary file and expect that your
program may be ported to non-UNIX environments.)


粗略的翻译一下:

linux中在mode中加上 'b' 仅仅是为了兼容C89。

但是windows平台上 ‘b’ 是为了以二进制形式进行IO。

为了提高可移植性,需要加上'b'。

那么为什么windows下要区分”文本模式“和”二进制模式“呢?

原因是windows使用CRLF(0x0D 0x0A)表示换行符(两个字节)。而*nix使用\n表示换行符。

在以”文本模式“读取文件时,会将读取到的CRLF(0x0D 0x0A)转化为单字节的0x0A,当遇到结束符CTRLZ(0x1A),就认为文件结束。

在以”文本模式“写文件时,会将所有的0x0A换成0x0D0x0A。

所以,在windows上打开linux上创建的文件会出现一些问题,原因就是换行符是不同的。

例如,有一个网络程序,需要在windows和linux之间传输文件,windows端的程序应该以二进制形式打开文件,然后进行传输。

这样才能将文件原封不动的传送到Linux。

然后Linux将文件传回时,windows以二进制方式接收,就可以得到原始文件了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: