注意:我看过帖子什么是scanf格式输入的cin analougus?在提问之前,这个帖子并没有解决我的问题.该帖子寻求C++ - 这样做的方式,但正如我已经提到的那样,使用C++是不方便的 - 有时这样做的方式,我有明确的例子.
我试图从istream对象中读取数据,有时候使用C++风格的方法(例如operator >>)是不方便的,例如数据是特殊形式的123:456所以你必须灌输':'作为space(非常hacky,而不是%d:scanf中的%d),或00123,你想要读取字符串并转换十进制而不是八进制(而不是scanf中的%d),以及可能的许多其他情况.
我选择istream作为接口的原因是因为它可以派生,因此更灵活.例如,我们可以创建内存流,或者动态生成的一些自定义流等.另一方面,C风格的文件*非常有限,至少在符合标准的方式下,创建自定义流.
所以我的问题是,有没有办法在istream对象上进行类似scanf的数据提取?我认为fscanf在内部使用fgetc从FILE*逐个字符地读取,而istream也提供这样的接口.因此可以通过复制和粘贴fscanf的代码并用istream对象替换FILE*来实现,但这非常hacky.是否有更聪明,更清洁的方式,还是有一些现有的工作?
谢谢.
zwo*_*wol 10
你应该从来没有,在任何情况下,使用scanf或者其亲属东西,原因有三:
%s,都同样危险gets.scanf它没有告诉你在遇到意外事件时它在输入中输入的字符有多远.scanf允许整个程序崩溃.在C++ 11之前,C++规范定义istream了数字格式的输入scanf,这意味着最后的异议很可能也适用于它们!(在C++ 11中,规范被改为使用,strto*而是在检测到溢出时做一些可预测的事情.)
你应该做的是:将整行输入读入std::string对象,用getline手工编码逻辑将它们分成几个字段(我不记得我脑子里的C++ - 字符串相当于什么strsep,但我'确定它存在)然后使用strtol/ strtod系列函数将数字字符串转换为机器号.
我不能强调这一点:在C或C++中将字符串转换为数字的唯一 100%可靠方式,除非你足够幸运地拥有在这方面已经符合C++ 11标准的C++运行时,具有这些strto*功能,你必须正确使用它们:
errno = 0;
result = strtoX(s, &ends, 10); // omit 10 for floats
if (s == ends || *ends || errno)
parse_error();
Run Code Online (Sandbox Code Playgroud)
(上面链接的OpenBSD联机帮助页解释了为什么你必须做这个相当复杂的事情.)
(如果你很聪明,你可以使用ends一些手动逻辑来跳过那个冒号,而不是strsep.)
根据@tmyklebu的评论,我实现了streamScanf,它通过fopencookie将istream包装为FILE*: https: //github.com/likan999/codejam/blob/master/Common/StreamScanf.cpp
| 归档时间: |
|
| 查看次数: |
2237 次 |
| 最近记录: |