c++ - sscanf 切换到新编译器后工作方式不同
问题描述
我在两个不同版本的编译器中有不同的 scanf 函数行为。
int number;
int offset = 0;
const char* ref = "123456";
sscanf(ref, "%d %n", &number, &offset);
我不明白为什么 Visual Studio 2013 版本 12.0 偏移 == 4 和 Visual Studio 2017 版本 15.9 偏移 == 6。它是旧版本的错误吗?当我删除空间时,两个版本都显示正确的数字:
sscanf(ref, "%d%n", &number, &offset);
%d%n 与 %d %n 有何不同?
解决方案
有什么
%d%n
不同%d %n
?
第一个只计算 消耗的字符%d
,而后者也计算任何可能跟随的空白字符。
#include <cstdio>
#include <iostream>
void test(const char * ref, const char * fmt)
{
std::cout << "fmt: \"" << fmt << "\" ref: \"" << ref << "\"" << std::endl;
int number;
int offset = 0;
int ret = std::sscanf(ref, fmt, &number, &offset);
std::cout << " - Returned: " << ret << " Offset: " << offset << " Number: " << number << std::endl;
}
int main(int argc, char* argv[])
{
test("123456", "%d %n");
test("123456", "%d%n");
test("123456 ", "%d %n"); // case 3
test("123456 ", "%d%n"); // case 4
}
(住在ideone上);输出:
fmt: "%d %n" ref: "123456" - Returned: 1 Offset: 6 Number: 123456 fmt: "%d%n" ref: "123456" - Returned: 1 Offset: 6 Number: 123456 fmt: "%d %n" ref: "123456 " - Returned: 1 Offset: 8 Number: 123456 fmt: "%d%n" ref: "123456 " - Returned: 1 Offset: 6 Number: 123456
请注意在案例 3 中如何计算 2 个附加的空白字符(因此偏移量 = 8),而在案例 4 中它们不被计算在内(因此偏移量 = 6)。
我不明白为什么 Visual Studio 2013 版本 12.0 偏移 == 4 和 Visual Studio 2017 版本 15.9 偏移 == 6。它是旧版本的错误吗?
这确实看起来像一个错误。可能性:
这
%d %n
被解释为在数字后需要空格%n
才能“生效”。您的输入“123456”没有后续空格,因此offset
未定义。这违反了标准,因为它清楚地表明格式字符串中的空白字符匹配输入字符串中的零个或多个空白字符。确切的措辞:“由空白字符组成的指令通过读取输入直到第一个非空白字符(仍然未读取)来执行,[..] 该指令永远不会失败。” ( N1570§7.21.6.2/5 )旧
sizeof(int)
平台上的 太小,无法代表数字123456
。最小允许有符号整数的最大值是
32767
(感谢@MartinYork)这意味着
sscanf
with%d
can only read12345
但 not123456
,因此将 the 留6
在输入中。这应该导致偏移量为 5 - 而不是 4 - 不过!
解决方案:确定您是否需要%d%n
或%d %n
首先需要语义,然后将测试用例添加到您的测试套件(您有,不是吗?)以确保提供的功能符合您的期望。如果需要,提供自己的实现。
推荐阅读
- android-studio - 如何停止java代码执行util webView中的链接在android studio中完全加载
- python - 虚拟环境的特定 jupyter notebook 配置文件
- mysql - 包含范围时,MySQL相关子查询非常慢
- python - 如何在 PyQt5 应用程序中显示来自 moviepy 的 write_audiofile 的转换进度?
- javascript - React-native-google-places-autocomplete:将动态字符串变量传递给查询
- swift - SwiftUI:当 JSON 文件从后端接收到新条目时,如何发送推送通知?
- outlook - 如何在 Outlook 的 VSTO 插件中获取 Outlook 的 Web 插件 ItemId?
- f# - 有没有办法连接两个 IActorRef 数组?
- python - pynput.keyboard 怎么能用到 f20?
- mongodb - Mongodb收集对象总小时收集