Using scanf() in C++ programs is faster than using cin?
Asked Answered
C

12

153

I don't know if this is true, but when I was reading FAQ on one of the problem providing sites, I found something, that poke my attention:

Check your input/output methods. In C++, using cin and cout is too slow. Use these, and you will guarantee not being able to solve any problem with a decent amount of input or output. Use printf and scanf instead.

Can someone please clarify this? Is really using scanf() in C++ programs faster than using cin >> something ? If yes, that is it a good practice to use it in C++ programs? I thought that it was C specific, though I am just learning C++...

Ceuta answered 25/6, 2009 at 3:58 Comment(6)
I'm curious what kind of problems they have where they think this will be an issue. Do you have a link to that site?Selenaselenate
My guess: bad programmer blames standard libraries for poor performance. Kind of like the always humorous "I think I found a bug in GCC" cry.Cinerama
@eclipse: the ACM problems I've worked on for competitions have a substantial amount of input/output and your program has to solve the questions in under something like 60 seconds... it becomes a real issue here.Hogback
--- that said, if you need to rely on scanf() for that extra performance boost, you're going about the problem the wrong way :)Hogback
this is some amusing thing about cin (scroll to where talks about its slowdown in his impl): unthought.net/c++/c_vs_c++.htmlTaperecord
Just as an observation - I played around with it, and on the 2nd problems (PRIME1) - using the same algorithm, both times, once using cin/cout and once with scanf/printf and the first version was faster than the second (but close enough that it's statistically irrelevant). This is one of the problems that is marked as being input/output intensive, and the method of input/output made no statistical difference whatsoever.Selenaselenate
P
251

Here's a quick test of a simple case: a program to read a list of numbers from standard input and XOR all of the numbers.

iostream version:

#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 version:

#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;
}

Results

Using a third program, I generated a text file containing 33,280,276 random numbers. The execution times are:

iostream version:  24.3 seconds
scanf version:      6.4 seconds

Changing the compiler's optimization settings didn't seem to change the results much at all.

Thus: there really is a speed difference.


EDIT: User clyfish points out below that the speed difference is largely due to the iostream I/O functions maintaining synchronization with the C I/O functions. We can turn this off with a call to 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;
}

New results:

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

C++ iostream wins! It turns out that this internal syncing / flushing is what normally slows down iostream i/o. If we're not mixing stdio and iostream, we can turn it off, and then iostream is fastest.

The code: https://gist.github.com/3845568

Popeyed answered 6/10, 2012 at 17:36 Comment(6)
I think the use of 'endl' may slowdown the execution.Installation
The use of std::endl is not in the loop.Popeyed
Makes no difference with sync on or off. Blame libc++ for that. It only boosts libstdc++Surmount
Do you think there is would be any difference between <cstdio> and <stdio.h>??Halfhearted
iostream loses when you parse more than one integer in one scanf call.Takamatsu
And then after you turn off syncing, what happens if someone adds a putchar() to your program?Hypophosphite
V
88

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

Performance of cin/cout can be slow because they need to keep themselves in sync with the underlying C library. This is essential if both C IO and C++ IO is going to be used.

However, if you only going to use C++ IO, then simply use the below line before any IO operations.

std::ios::sync_with_stdio(false);

For more info on this, look at the corresponding libstdc++ docs.

Vocational answered 11/4, 2013 at 1:27 Comment(1)
also use cin.tie(static_cast<ostream*>(0)); for better performanceRepellent
I
43

Probably scanf is somewhat faster than using streams. Although streams provide a lot of type safety, and do not have to parse format strings at runtime, it usually has an advantage of not requiring excessive memory allocations (this depends on your compiler and runtime). That said, unless performance is your only end goal and you are in the critical path then you should really favour the safer (slower) methods.

There is a very delicious article written here by Herb Sutter "The String Formatters of Manor Farm" who goes into a lot of detail of the performance of string formatters like sscanf and lexical_cast and what kind of things were making them run slowly or quickly. This is kind of analogous, probably to the kind of things that would affect performance between C style IO and C++ style. The main difference with the formatters tended to be the type safety and the number of memory allocations.

Iceni answered 25/6, 2009 at 4:3 Comment(0)
W
22

I just spent an evening working on a problem on UVa Online (Factovisors, a very interesting problem, check it out):

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

I was getting TLE (time limit exceeded) on my submissions. On these problem solving online judge sites, you have about a 2-3 second time limit to handle potentially thousands of test cases used to evaluate your solution. For computationally intensive problems like this one, every microsecond counts.

I was using the suggested algorithm (read about in the discussion forums for the site), but was still getting TLEs.

I changed just "cin >> n >> m" to "scanf( "%d %d", &n, &m )" and the few tiny "couts" to "printfs", and my TLE turned into "Accepted"!

So, yes, it can make a big difference, especially when time limits are short.

Welfarism answered 12/10, 2009 at 7:19 Comment(0)
C
6

If you care about both performance and string formatting, do take a look at Matthew Wilson's FastFormat library.

edit -- link to accu publication on that library: http://accu.org/index.php/journals/1539

Christinchristina answered 25/6, 2009 at 8:0 Comment(2)
Agree completely. But you need to be aware that FastFormat is only for output. It has no input/read facilities. (Not yet, anyway)Anoa
Unfortunately that link seems to be dead. Here's a Wayback Machine copy: web.archive.org/web/20081222164527/http://fastformat.orgPopeyed
I
5

The statements cin and cout in general use seem to be slower than scanf and printf in C++, but actually they are FASTER!

The thing is: In C++, whenever you use cin and cout, a synchronization process takes place by default that makes sure that if you use both scanf and cin in your program, then they both work in sync with each other. This sync process takes time. Hence cin and cout APPEAR to be slower.

However, if the synchronization process is set to not occur, cin is faster than scanf.

To skip the sync process, include the following code snippet in your program right in the beginning of main():

std::ios::sync_with_stdio(false);

Visit this site for more information.

Invoice answered 19/10, 2014 at 8:53 Comment(0)
S
2

There are stdio implementations (libio) which implements FILE* as a C++ streambuf, and fprintf as a runtime format parser. IOstreams don't need runtime format parsing, that's all done at compile time. So, with the backends shared, it's reasonable to expect that iostreams is faster at runtime.

Sourdough answered 25/6, 2009 at 7:55 Comment(2)
I don't think so. I think GNU's libc is pure C and assembly.Overload
That doesn't make it better.Catbird
N
1

Yes iostream is slower than cstdio.
Yes you probably shouldn't use cstdio if you're developing in C++.
Having said that, there are even faster ways to get I/O than scanf if you don't care about formatting, type safety, blah, blah, blah...

For instance this is a custom routine to get a number from 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;
}
Northerly answered 26/4, 2011 at 15:17 Comment(1)
getchar_unlocked() is non-standard , and available for gcc not visual studioRepellent
C
0

The problem is that cin has a lot of overhead involved because it gives you an abstraction layer above scanf() calls. You shouldn't use scanf() over cin if you are writing C++ software because that is want cin is for. If you want performance, you probably wouldn't be writing I/O in C++ anyway.

Cot answered 25/6, 2009 at 4:4 Comment(2)
Is cin really more "abstract" (at runtime) than scanf? I don't think so... scanf must interpret the format string at runtime, whereas the iostream knows the format at compile-time.Popeyed
@nibot: The type is known at compile-time but not the format. Whether the input is expected to be hexadecimal or not for example is entirely dependent on how the std::istream is configured at runtime (via I/O manipulators or by setting flags on the istream object itself). A FILE* object on the other hand has no such state, so a call to scanf in this regard is much more stable.Cot
D
0

Of course it's ridiculous to use cstdio over iostream. At least when you develop software (if you are already using c++ over c, then go all the way and use it's benefits instead of only suffering from it's disadvantages).

But in the online judge you are not developing software, you are creating a program that should be able to do things Microsoft software takes 60 seconds to achieve in 3 seconds!!!

So, in this case, the golden rule goes like (of course if you dont get into even more trouble by using java)

  • Use c++ and use all of it's power (and heaviness/slowness) to solve the problem
  • If you get time limited, then change the cins and couts for printfs and scanfs (if you get screwed up by using the class string, print like this: printf(%s,mystr.c_str());
  • If you still get time limited, then try to make some obvious optimizations (like avoiding too many embedded for/while/dowhiles or recursive functions). Also make sure to pass by reference objects that are too big...
  • If you still get time limited, then try changing std::vectors and sets for c-arrays.
  • If you still get time limited, then go on to the next problem...
Dorothi answered 27/4, 2010 at 2:47 Comment(0)
E
0
#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;
}

There's a bug at the end of the file, but this C code is dramatically faster than the faster C++ version.

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

The original C++ took 30sec the C code took 2sec.

Edmundedmunda answered 4/5, 2017 at 16:58 Comment(0)
A
-5

Even if scanf were faster than cin, it wouldn't matter. The vast majority of the time, you will be reading from the hard drive or the keyboard. Getting the raw data into your application takes orders of magnitude more time than it takes scanf or cin to process it.

Albite answered 25/6, 2009 at 4:2 Comment(4)
What about IPC through pipes? Do you think there might be a noticeable performance hit there?Cot
Even with IPC through pipes, much more time is spent going in and out of the kernel than just parsing it with scanf/cin.Albite
I did tests in this area, and certainly cout & cin suck performance. While for user input it's negligible, it's certainly not so for things where performance matters. Other c++ framework exist that are faster, though.Taperecord
The problem is that iostream is slower than hdd. Yes, it sucks that much.Lickerish

© 2022 - 2024 — McMap. All rights reserved.