gpt4 book ai didi

c++ - istream 对象上的 scanf

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:14:11 27 4
gpt4 key购买 nike

注意:我在提问之前看过 What is the cin analougus of scanf formatted input? 帖子,但该帖子并没有解决我的问题。该帖子寻求 C++ 方式来完成它,但正如我已经提到的,有时只使用 C++ 方式来完成它是不方便的,我有明确的例子。

我正在尝试从 istream 对象中读取数据,有时仅使用 C++ 风格的方式(例如运算符>>)是不方便的,例如数据是特殊形式 123:456 所以你必须灌输使 ':' 成为空格(这是非常 hacky,而不是 scanf 中的 %d:%d),或者 00123 你想读取为字符串并转换十进制而不是八进制(与 scanf 中的 %d 相反),可能还有许多其他情况。

之所以选择istream作为接口(interface),是因为它可以派生,因此更加灵活。例如,我们可以创建内存中的流,或者一些动态生成的自定义流等。另一方面,C 风格的 FILE* 在创建自定义方面非常有限,至少在符合标准的方式上如此流。

所以我的问题是,有没有办法在 istream 对象上进行类似 scanf 的数据提取?我认为 fscanf 在内部使用 fgetc 从 FILE* 逐字符读取,而 istream 也提供了这样的接口(interface)。因此,可以通过复制和粘贴 fscanf 的代码并将 FILE* 替换为 istream 对象来实现,但这非常 hacky。是否有更智能、更清洁的方法,或者是否有一些现有的工作?

谢谢。

最佳答案

在任何情况下,您都不应永远使用scanf 或其亲属任何,原因有以下三个:

  1. 许多格式字符串,例如 %s 的所有简单用法,都与 gets 一样危险。
  2. 从格式错误的输入中恢复几乎是不可能的,因为 scanf 不会告诉您当它遇到意外情况时它得到的输入有多远字符数
  3. 数字溢出会触发未定义的行为:是的,这意味着如果输入中的数字字段有太多数字,scanf 可以使整个程序崩溃

在 C++11 之前,C++ 规范根据 scanf 定义了 istream 格式的数字输入,这意味着 last objection 很可能适用于它们还有! (在 C++11 中,规范改为使用 strto* 并在检测到溢出时执行一些可预测的操作。)

您应该做的是:使用 getline 将整行输入读入 std::string 对象,手动编写逻辑将它们拆分为字段(我不记得我脑海中的 strsep 的 C++ 字符串等价物是什么,但我确定它存在)然后使用 strtol 将数字字符串转换为机器号/strtod函数族。

我怎么强调都不为过:只有 100% 可靠的方法可以在 C 或 C++ 中将字符串转换为数字,除非您有幸拥有一个 C++ 运行时在这方面已经符合 C++11,具有 strto* 功能,您必须正确使用它们:

errno = 0;
result = strtoX(s, &ends, 10); // omit 10 for floats
if (s == ends || *ends || errno)
parse_error();

(上面链接的 OpenBSD 联机帮助页解释了为什么你必须做这个相当复杂的事情。)

(如果你够聪明,你可以使用 ends 和一些手动逻辑来跳过那个冒号,而不是 strsep。)

关于c++ - istream 对象上的 scanf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24302160/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com