今天写这篇博客纯粹就是遇到点问题,不知道有没有人遇到过。
背景
最近打CF的时候发现交上去一个答案发生了非预期退出,而且是在样例里面发生的,于是我赶紧把程序扒下来最大限度地确定出现问题的代码段,最终出现了以下代码写的程序。
1 |
|
首先万能头文件,然后我打开了一个文件把标准输入流重定向到一个文件中,并且关闭了 $cin$ 和 $cout$ 的同步流,大概率问题是出在这里的,然后就一些常规操作没什么好说的。
我的 $1.in$ 的文件内容如下图所示:
是正常的输入数据,并且文件编码为 $UTF-8$ 没有任何问题。
测试
那么我们开 $DEV$ 运行以下先。
可以看到程序运行出现了非预期结果。
由于 $DEV$ 不方便调试我们便把 $IDE$ 换成了 $VScode$ 。
这里我们在 $scanf$ 和 $printf$ 分别打一个断点,然后开启调试模式。
这里 $s$ 和 $t$ 是随机值正常,因为我们并没有初始化 $s$ 和 $t$ 。
那么我们 $F10$ 步过看看结果。
过了 $scanf$ 却没有成功读入数据!!!这是为什么?
我开始尝试找不同的原因,原因1就是怀疑文件读入的问题,所以我们先注释重定向那一行测试看看。
运行结果是正常的,这么看来问题似乎解决了。
但是提交给oj是实实在在地报错了,因此我们尝试注释其它代码看看情况,这里我们接着选择注释这个关闭同步流的代码。
这回居然正常读入了数据!什么鬼?
因为刚刚我把 $freopen$ 注释了是确确实实读入没有什么问题了,但是现在似乎把
1 | ios::sync_with_stdio(false); |
给关闭了程序也是能正常进行的。
而且这里我还测试了第三种情况:两者都打开,把 $long long$ 换回 $int$ 类型。
居然也是正常读入?也就是说,打开文件,在关闭同步流的情况下使用 $scanf$ 读入 $long long$ 数据类型会导致读入不成功,而且注释了打开文件提交给 oj 测评返回了错误结果。
总结
我个人感觉可能涉及到底层的一些问题了。因为自己测试确实三种情况同时满足会导致读入数据失败。这三种情况分别是
- 重定向 $stdin$ 到一个文件
- 关闭IO同步流
- 用 $scanf$ 读入 $long long$ 数据
一般来说,$scanf$ 不接收到 $EOF$ 信号是会一直等待你输入的。常见的 $EOF$ 基本就是读到文件尾,或者手动给终端了一个 $Ctrl + Z$ 信号给程序,这应该算外部中断了。就基本不会遇到 $scanf$ 读入失败的情况。要真的能有这么好数据那不是可以随便泄露?如果上一个栈帧保存的一些变量的地址刚好在这,我这里故意读入失败那就直接泄露地址,我没见过这样的情况。
当然我比较浅薄,只能看到表面上的一些东西,如果你有深层次点的合理的解释麻烦你也联系我,我也不想就在这里留一个错误的结论,期待这个问题能早点解决。
下面我也给出以下本次实验用到的附件供大家测试,看看能不能是版本的问题。