tellp()和tellg()分别返回输出流和输入流的当前位置,仅对支持随机访问的流(如fstream、stringstream)有效;对cin/cout等终端流返回-1,且文本模式下可能失准,应使用二进制模式并检查返回值。

怎么用 tellp() 和 tellg() 获取当前读写位置
这两个函数分别返回输出流(ostream)和输入流(istream)内部缓冲区的当前位置,但**只对支持随机访问的流有效**,比如 std::fstream 或 std::stringstream;对 std::cout、std::cin 这类终端流调用会返回 -1。
实操建议:
-
tellp()用在std::ofstream或std::fstream(以std::ios::out打开)上,表示「下一次写入将从哪个字节开始」 -
tellg()用在std::ifstream或std::fstream(以std::ios::in打开)上,表示「下一次读取将从哪个字节开始」 - 若流是双向的(
std::fstream),必须先执行一次seekg()或seekp(),或至少有一次读/写操作,否则初始位置可能未定义(尤其 Windows 下常返回 -1)
为什么有时 tellg() 返回 -1?常见原因和绕过方法
最典型的情况是:流没打开、打开失败、或底层文件不支持随机访问(如管道、TTY 设备)。但更隐蔽的是——std::ifstream 在文本模式下读取换行符时,tellg() 可能失准,因为 C++ 标准允许实现对 \r\n 做透明转换,导致返回的偏移量与实际文件字节位置不一致。
实操建议:
- 始终检查返回值是否为 -1:
if (f.tellg() == -1) { /* 失败 */ } - 需要精确字节定位时,**务必用二进制模式打开**:
std::ifstream f("a.txt", std::ios::binary) - 不要依赖
tellg()在文本流中“回退”到刚读过的字符——unget()或peek()更可靠
tellp() 和 tellg() 在 std::fstream 中能混用吗
可以,但有严格前提:流必须以 std::ios::in | std::ios::out 方式打开,且每次切换读/写方向前,**必须调用 seekg() 或 seekp() 显式重定位**,否则行为未定义(C++ 标准明确指出)。很多新手直接 read() 后立刻 tellp(),结果得到垃圾值。
实操建议:
- 写完后想查写位置?先
flush(),再tellp() - 读完想查读位置?直接
tellg()即可(前提是没切方向) - 如果刚读完又想写,必须先
seekp(tellg())或类似操作,不能假设两个指针同步 - Windows 下用
std::fstream读写同一文件时,强烈建议加std::ios::binary,避免文本模式换行符干扰
替代方案:什么时候不该用 tellg()/tellp()
当目标不是“获取当前流位置”,而是“统计已处理多少字节”或“记录日志偏移”,硬靠 tellg() 反而容易出错——比如中间有 ignore()、getline() 跳过内容,或异常中断导致位置滞后。
实操建议:
- 做日志解析或协议解析时,自己维护一个
size_t offset = 0,每次read(buf, n)后手动累加n - 需要反复跳转的场景(如解析 ELF、PNG),优先用
seekg(pos, std::ios::beg)定位,而不是靠tellg()推算 -
std::stringstream虽然支持tellp(),但其内部缓冲可能动态扩容,返回值仅反映逻辑位置,不等于内存地址偏移
真正麻烦的从来不是调用函数本身,而是搞不清它反映的是「流缓冲视图」还是「底层文件字节位置」——尤其跨平台时,文本模式那点隐式转换,足够让 tellg() 的返回值变成玄学。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











