最近使用fseek时遇到一个问题,fseek的函数原型如下:
int fseek(FILE *stream, long offset, int whence);
可是我在使用的时候犯了一个错误,我把fseek的第二个参数和第三个参数的位置弄错了。
而且我没有检测fseek的返回值,导致程序出错。(发现自己太low了.......)
为此我首先查看了当前环境的glibc的版本。
直接运行libc.so.6会输出glibc的版本,或者使用 “ldd --version”也是可以的,我的glibc的版本是 2.15
huntinux@ubuntu-chj:~/Downloads/glibc-2.15$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu EGLIBC 2.15-0ubuntu10.12) stable release version 2.15, by Roland McGrath et al.
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.6.3.
Compiled on a Linux 3.2.68 system on 2015-03-26.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.
于是我下载了glibc-2.15的源码找到了fseek的源码
/* ./libio/fseek.c */
int
fseek (fp, offset, whence)
_IO_FILE* fp;
long int offset;
int whence;
{
int result;
CHECK_FILE (fp, -1);
_IO_acquire_lock (fp);
result = _IO_fseek (fp, offset, whence);
_IO_release_lock (fp);
return result;
}
/* libio/iolibio.h */
#define _IO_fseek(__fp, __offset, __whence) \
(_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) \
== _IO_pos_BAD ? EOF : 0)
/* libio/libioP.h */
#define _IO_seek_set 0
#define _IO_seek_cur 1
#define _IO_seek_end 2
/* posix/unistd.h */
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Seek from end of file. */
/* libio/ioseekoff.c */
_IO_off64_t
_IO_seekoff_unlocked (fp, offset, dir, mode)
_IO_FILE *fp;
_IO_off64_t offset;
int dir;
int mode;
{
if (dir != _IO_seek_cur && dir != _IO_seek_set && dir != _IO_seek_end)
{
__set_errno (EINVAL);
return EOF;
}
/* If we have a backup buffer, get rid of it, since the __seekoff
callback may not know to do the right thing about it.
This may be over-kill, but it'll do for now. TODO */
if (mode != 0 && ((_IO_fwide (fp, 0) < 0 && _IO_have_backup (fp))
|| (_IO_fwide (fp, 0) > 0 && _IO_have_wbackup (fp))))
{
if (dir == _IO_seek_cur && _IO_in_backup (fp))
{
if (_IO_vtable_offset (fp) != 0 || fp->_mode <= 0)
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
else
abort ();
}
if (_IO_fwide (fp, 0) < 0)
INTUSE(_IO_free_backup_area) (fp);
else
INTUSE(_IO_free_wbackup_area) (fp);
}
return _IO_SEEKOFF (fp, offset, dir, mode);
}
其中:
if (dir != _IO_seek_cur && dir != _IO_seek_set && dir != _IO_seek_end)
{
__set_errno (EINVAL);
return EOF;
}
是检查fseek的第三个参数whence的值,是否为 SEEK_CUR SEEK_SET SEEK_END。 如果不是就返回EOF(-f), 并设置错误码为EINVAL。
这与manpage中的描述是一致的。
man page是这样写的:
RETURN VALUE
The rewind() function returns no value. Upon successful completion, fgetpos(), fseek(), fsetpos() return 0, and ftell() returns the current offset. Oth‐
erwise, -1 is returned and errno is set to indicate the error.
ERRORS
EBADF The stream specified is not a seekable stream.
EINVAL The whence argument to fseek() was not SEEK_SET, SEEK_END, or SEEK_CUR.
总结:
养成良好的习惯,要检查函数返回值!