在C ++程序中使用scanf()比使用cin更快?

我不知道这是不是真的,但是当我在提供网站的问题之一阅读FAQ时,发现了一些东西,引起了我的注意:

检查你的input/输出方法。 在C ++中,使用cin和cout太慢了。 使用这些,你会保证不能解决任何问题,一个体面的数量input或输出。 改用printf和scanf。

有人可以澄清这一点? 真的在C ++程序中使用scanf()比使用cin >>东西更快吗? 如果是的话,那么在C ++程序中使用它是一个好习惯吗? 我认为这是C具体的,虽然我只是学习C ++ …

下面是一个简单案例的快速testing:一个程序从标准input读取数字列表,并将所有数字异或。

iostream版本:

#include <iostream> int main(int argc, char **argv) { int parity = 0; int x; while (std::cin >> x) parity ^= x; std::cout << parity << std::endl; return 0; } 

scanf版本:

 #include <stdio.h> int main(int argc, char **argv) { int parity = 0; int x; while (1 == scanf("%d", &x)) parity ^= x; printf("%d\n", parity); return 0; } 

结果

使用第三个程序,我生成了一个包含33,280,276个随机数字的文本文件。 执行时间是:

 iostream version: 24.3 seconds scanf version: 6.4 seconds 

改变编译器的优化设置似乎并没有改变结果。

因此:确实存在速度差异。


编辑:用户clyfish 指出下面的速度差异主要是由于保持与CI / Ofunction同步的iostream I / Ofunction。 我们可以通过调用std::ios::sync_with_stdio(false);来closures它std::ios::sync_with_stdio(false);

 #include <iostream> int main(int argc, char **argv) { int parity = 0; int x; std::ios::sync_with_stdio(false); while (std::cin >> x) parity ^= x; std::cout << parity << std::endl; return 0; } 

新的结果:

 iostream version: 21.9 seconds scanf version: 6.8 seconds iostream with sync_with_stdio(false): 5.5 seconds 

C ++ iostream获胜! 事实certificate,这种内部同步/刷新通常是减慢iostream I / O。 如果我们不混合cstdio和iostream,我们可以closures它,然后iostream是最快的。

代码: https : //gist.github.com/3845568

http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma

cin / cout的性能可能会很慢,因为它们需要保持与底层C库同步。 如果要使用CIO和C ++ IO,这是非常重要的。

但是,如果只打算使用C ++ IO,则只需在任何IO操作之前使用下面的行

 std::ios::sync_with_stdio(false); 

有关更多信息,请参阅libstdc ++文档: http : //gcc.gnu.org/onlinedocs/libstdc++/manual/io_and_c.html

可能scanf比使用stream有点快。 尽pipestream提供了很多types的安全性,并且不需要在运行时parsing格式化string,但它通常具有不需要过多的内存分配的优点(这取决于您的编译器和运行时)。 这就是说,除非性能是你唯一的最终目标,而你正处于关键的道路上,那么你应该更喜欢安全(较慢)的方法。

有一个非常好吃的文章,由Herb Sutter写的“ 庄园农场的string格式 ”,详细介绍了像sscanflexical_cast这样的string格式化程序的性能,以及使得它们缓慢或者快速运行的东西。 这是类似的,可能是那种会影响C风格IO和C ++风格之间的性能的东西。 与格式化程序的主要区别往往是types安全性和内存分配的数量。

我只是花了一个晚上在UVA在线(Factovisors,一个非常有趣的问题,看看)的问题上工作:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=35&page=show_problem&problem=1080

我在提交时收到了TLE(超出时间限制)。 在解决在线评判站点的这些问题上,您可能需要2-3秒的时间来处理数千个用于评估您的解决scheme的testing用例。 对于像这样的计算密集型问题,每微秒计数。

我正在使用build议的algorithm(在网站的讨论论坛上阅读),但仍然得到TLEs。

我把“cin >> n >> m”改成了“scanf(”%d%d“,&n,&m)”和几个小小的“cout”改为“printfs”,我的TLE变成了“Accepted”!

所以,是的,这可以造成很大的差别,特别是在时间限制很短的时候。

哇,谈谈过早的优化。 如果不是一个可笑的优化。 在cin >> x最大化您的quadcore CPU之前,I / O会在你的程序中cin >> x瓶颈。

好的,嗤之以鼻:不,不好的做法是将<iostream>换成<cstdio> 。 在C ++中使用C ++库。 不要使用scanf ,不要调用malloc ,不要传递,不要收200美元。

如果您关心性能和string格式,请查看Matthew Wilson的FastFormat库。

编辑 – 链接到该图书馆的精确出版物: http : //accu.org/index.php/journals/1539

是的,iostream比cstdio慢。
是的,如果你用C ++开发,你可能不应该使用cstdio。
话虽如此,如果你不关心格式化,input安全性,等等,等等,那么有更快的方法来获取I / O比scanf …

例如,这是一个自定义例程来从STDIN获得一个数字:

 inline int get_number() { int c; int n = 0; while ((c = getchar_unlocked()) >= '0' && c <= '9') { // n = 10 * n + (c - '0'); n = (n << 3) + ( n << 1 ) + c - '0'; } return n; } 

有stdio实现( libio )实现FILE *作为C ++ streambuf,fprintf作为运行时格式parsing器。 IOstream不需要运行时格式parsing,这一切都是在编译时完成的。 因此,在后端共享的情况下,可以期望iostream在运行时更快。

问题是cin有很多的开销,因为它给了你一个scanf()调用之上的抽象层。 如果你正在编写C ++软件,你不应该使用scanf() ,因为这是cin目的。 如果你想要performance,你可能不会用C ++编写I / O。

 #include <stdio.h> #include <unistd.h> #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) static int scanuint(unsigned int* x) { char c; *x = 0; do { c = getchar_unlocked(); if (unlikely(c==EOF)) return 1; } while(c<'0' || c>'9'); do { //*x = (*x<<3)+(*x<<1) + c - '0'; *x = 10 * (*x) + c - '0'; c = getchar_unlocked(); if (unlikely(c==EOF)) return 1; } while ((c>='0' && c<='9')); return 0; } int main(int argc, char **argv) { int parity = 0; unsigned int x; while (1 != (scanuint(&x))) { parity ^= x; } parity ^=x; printf("%d\n", parity); return 0; } 

忘记它可能只是testing是否重要。 文件末尾有一个错误,但是这个C代码比快速的cpp版本快得多。

 paradox@scorpion 3845568-78602a3f95902f3f3ac63b6beecaa9719e28a6d6 ▶ make test time ./xor-c < rand.txt 360589110 real 0m11,336s user 0m11,157s sys 0m0,179s time ./xor2-c < rand.txt 360589110 real 0m2,104s user 0m1,959s sys 0m0,144s time ./xor-cpp < rand.txt 360589110 real 0m29,948s user 0m29,809s sys 0m0,140s time ./xor-cpp-noflush < rand.txt 360589110 real 0m7,604s user 0m7,480s sys 0m0,123s 

原来的CPP是30秒,这是2秒。

一般使用的语句cincout似乎比c ++中的scanfprintf慢,但实际上它们更快!

问题是:在C ++中,无论何时使用cincout ,默认情况下都会发生同步过程,以确保如果在程序中同时使用scanfcin ,则它们将彼此同步。 此同步过程需要时间。 因此cincout APPEAR会变慢。

但是,如果同步过程设置为不发生,则cinscanf快。

要跳过同步过程,请在main()的开始部分在程序中包含以下代码片段:

 std::ios::sync_with_stdio(false); 

访问此网站获取更多信息。

即使scanfcin快,也没关系。 绝大多数时候,你将会从硬盘或键盘上读取数据。 获取原始数据到您的应用程序需要更多的时间比scanfcin处理它需要更多的时间。

当然,通过iostream使用cstdio是很荒谬的。 至less当你开发软件的时候(如果你已经在使用c ++而不是c了,那就去一路使用,而不是仅仅因为缺点而受益)。

但在网上裁判你没有开发软件,你正在创build一个程序,应该能够做的事情微软软件需要60秒,在3秒内实现!

所以,在这种情况下,黄金法则就像(当然,如果你不使用java进入更麻烦)

  • 使用c ++,并使用它的所有function(和沉重/缓慢)来解决问题
  • 如果你有时间限制,然后改变printfs和scanfs的cins和cout(如果你使用类string搞砸了,打印如下:printf(%s,mystr.c_str());
  • 如果你仍然有时间限制,然后尝试做一些明显的优化(例如避免太多embedded/ / / dowhiles或recursion函数)。 还要确保通过太大的引用对象传递…
  • 如果仍然有时间限制,那么尝试更改std :: vectors并为c数组设置。
  • 如果你仍然有时间限制,然后继续下一个问题…