• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[c++] cin, cout VS printf, scanf ?

Status
Not open for further replies.

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
Simple question, what's the difference between them?

EDIT:
actually I have a question about how to detect immediately when user press any keyboard button, as example I have a variable named temp[1] = 0, then when user pressed "1" then at the monitor appears 0 right after user press the key (without pressing "enter" first), I'm creating a simple hangman game actually..
 
Here is a good explanation:
http://www.parashift.com/c++-faq-lite/iostream-vs-stdio.html

Of course, iostream has extra overhead, but that is usually insignificant to the program. Usually people will choose the C++ cin/cout because it is considered fitting to the "C++ style". You'll hear that come up a lot with languages in general (especially python--to do things a "pythonic" way). Usually there is some overarching style behind a particular language, depending on the language's goals, so it is considered better to follow that style. So I would personally use cin/cout unless you have a good reason not to.
 
Level 25
Joined
May 11, 2007
Messages
4,651
Printf is C's version for printing out things, while Cout is C++'s way, while Console.writeline is C#'s way.

So they work in the same way, except Cout is a bit easier to use. So use that if you're going to code in C++.

Same thing with Scanf, it's C's way of inputting things, use Cin >> for C++.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Printf is a very heavy function. It should only be used for generating natural language strings. It should never be used in performance code due to the format parsing overhead.

For performance code use some form of stream directly.

actually I have a question about how to detect immediately when user press any keyboard button, as example I have a variable named temp[1] = 0, then when user pressed "1" then at the monitor appears 0 right after user press the key (without pressing "enter" first), I'm creating a simple hangman game actually..
Use an input library. In Linux this is probably done by opening an input stream from the input driver file. In Windows you use their input library from DirectX. Some Window management libraries have input as part of them.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Printf is a very heavy function. It should only be used for generating natural language strings. It should never be used in performance code due to the format parsing overhead.

For performance code use some form of stream directly.


Use an input library. In Linux this is probably done by opening an input stream from the input driver file. In Windows you use their input library from DirectX. Some Window management libraries have input as part of them.

I dont know about the input libraries you are talking about(DirectX libs etc), but considering C++ streams vs C printf, check this script:

C++:
#include <iostream>
#include <cstdio>
#include <string>

class Benchmark{
	long long startT;
	bool paused;
	long long lastPRet;
public:
	Benchmark() : startT(__rdtsc()), paused(false), lastPRet(0) {}
	long long pause()
	{
		if (paused)
			return lastPRet;

		paused = true;
		return lastPRet = __rdtsc() - startT;
	}
	long long get()
	{
		return __rdtsc() - startT;
	}

	void start()
	{
		paused = false;
		startT = __rdtsc();
	}
};

#include <random>
#include <chrono>

int main()
{
	const int LOOPTIMES = 10000;
	const float CPU_CLOCK_APPROX = 3600000000.f;

	std::vector<int> randInfo;

	auto currentTime = std::chrono::high_resolution_clock::now().time_since_epoch().count();
	std::mt19937 generator(currentTime);

	//generate random info:
	for(int i = 0; i < LOOPTIMES; ++i)
	{
		randInfo.push_back(generator());
	}

	Benchmark m;

	m.start();
	
	for(int i = 0; i < LOOPTIMES; ++i)
	{
		printf("Number %d: %d\n", i, randInfo[i]);
	}

	auto pPrintf = m.get() / CPU_CLOCK_APPROX;

	m.start();
	
	for(int i = 0; i < LOOPTIMES; ++i)
	{
		std::cout << "Number " << i << ": " << randInfo[i] << "\n";
	}

	auto pCout = m.get() / CPU_CLOCK_APPROX;

	std::cout << "\n\n\nLooping " << LOOPTIMES << " times:\n";
	std::cout << "\tprinf(): " << pPrintf << " sec\n";
	std::cout << "\tcout << ...: " << pCout << " sec\n";

	std::cin.get();
}

this script outputs:

Looping 10000 times:
printf(): 0.972621 sec
cout << ...: 14.7 secs

Yes the numbers vary between runs roughly by 10%, but still as you see, printf is a loot quicker than C++ ostream object cout.

This is because while printf has some formatting to do, it is still only 1 function call, and the equivalent cout is actually 5 function calls. Dont forget that ostream inherits from basic_ios and that inherits from ios_base. + the guts of << operator has to check whether the stream state is goodbit(otherwise the operation cannot proceed), it must construct sentry and do checks with that, then it has to get the buf object(streambuf type) and it all calls virtual methods, which must be dispatched, further increasing overhead.

The code was run on default Release mode on Visual studio 2012.

On the other hand, printf has no compile-time checks for types passed, so even printf("%d", std::vector<std::string>(5)[0]); is valid, but will result in garbage printed.

Back on topic, what you want to do is not nativelly possible, you must use System specific ways to do it. Here is a link Ive found: http://stackoverflow.com/questions/...dard-input-without-waiting-for-enter-to-be-pr that may be of help
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
This is because while printf has some formatting to do, it is still only 1 function call, and the equivalent cout is actually 5 function calls. Dont forget that ostream inherits from basic_ios and that inherits from ios_base. + the guts of << operator has to check whether the stream state is goodbit(otherwise the operation cannot proceed), it must construct sentry and do checks with that, then it has to get the buf object(streambuf type) and it all calls virtual methods, which must be dispatched, further increasing overhead.
Well what do you expect if you do the silly thing of calling OS system calls 5 times instead of once?

Either buffer the output so it calls the os I/O less, or merge the string together before printing it. The idea is that you have the same number of I/O calls except that one of them uses a generated string using string logic where as the other uses a formatted string. As soon as any sort of I/O kernel level swap is involved any bench mark difference in performance goes out the window. The only thing you have proved is that I/O is very slow and that compared with printf, removing a single I/O call will be much more of an optimization.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Ive changed the loop for the cout test to

C++:
	for(int i = 0; i < LOOPTIMES; ++i)
	{
		std::string s = "Number " + std::to_string(i) + ": " + std::to_string(randInfo[i]) + "\n";
		std::cout << s;
	}

and it is still the same, 1 second vs 14.9

edit: Even if I directly access the stream object as so:

C++:
	for(int i = 0; i < LOOPTIMES; ++i)
	{
		std::string s = "Number " + std::to_string(i) + ": " + std::to_string(randInfo[i]) + "\n";
		std::cout.rdbuf()->sputn(&s[0], s.size());
	}

its still the same speed.

There is no denying that C++ streams are slow, even the members of C++ committee knows about this, but they said that they didnt find more efficient way yet to do it. If you feel you know of something faster, propose it to C++ standard committee
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Default C++ strings are probably not allocation optimized for multiple concatenations. Using a suitable sized character array and manually managing the string might be faster as it avoids the dynamic allocation overhead of c++ strings. Formated printing may use such a buffer internally so only be subject to a memory copy as opposed to multiple full blown memory allocations. Memory allocations can result in OS system calls which would also explain the huge slowness.

A lot of people under estimate the overhead of short lived objects being created and destroyed from the memory allocation point of view. Without extending their life time, simply having an object cache or pool can greatly improve performance at the cost of a larger process address space and potentially less page cohesion.

Memory allocation is only very slow when new pages of virtual memory are required. These can only be requested from the OS (as it has to modify page mappings) so generate a kernel level call. Equally well it is slow when freeing all elements on a page as then the virtual memory page has to be de-allocated which also requires a kernel level call. Obviously sub-page allocation and freeing (done within an already existing page that is not completely clear) is done entirely within process address space so is performed a lot faster. Something silly like your strings constantly allocating and de-allocating a page from the process with each loop would result in very poor performance for even the most trivial of tasks.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
I personally dont think it is much of a problem, if you are printing > 600 lines/second into console, you are doing something wrong

But just to prove that printf is order of maginute faster than cout, here is the best test that you can get:

C++:
#include <iostream>
#include <cstdio>
#include <string>

class Benchmark{
	long long startT;
	bool paused;
	long long lastPRet;
public:
	Benchmark() : startT(__rdtsc()), paused(false), lastPRet(0) {}
	long long pause()
	{
		if (paused)
			return lastPRet;

		paused = true;
		return lastPRet = __rdtsc() - startT;
	}
	long long get()
	{
		return __rdtsc() - startT;
	}

	void start()
	{
		paused = false;
		startT = __rdtsc();
	}
};

#include <random>
#include <chrono>

int main()
{
	const int LOOPTIMES = 10000;
	const float CPU_CLOCK_APPROX = 3600000000.f;

	std::vector<int> randInfo;

	auto currentTime = std::chrono::high_resolution_clock::now().time_since_epoch().count();
	std::mt19937 generator(currentTime);

	//generate random info:
	for(int i = 0; i < LOOPTIMES; ++i)
	{
		randInfo.push_back(generator());
	}

	Benchmark m;
	
	long long pTotal = 0;

	for(int i = 0; i < LOOPTIMES; ++i)
	{
		m.start();
		printf("Number %d: %d\n", i, randInfo[i]);
		pTotal += m.get();
	}

	auto pPrintf = pTotal / CPU_CLOCK_APPROX;
	
	long long cTotal = 0;

	for(int i = 0; i < LOOPTIMES; ++i)
	{
		std::string s = "Number " + std::to_string(i) + ": " + std::to_string(randInfo[i]) + "\n";

		m.start();
		std::cout.rdbuf()->sputn(&s[0], s.size());
		cTotal += m.get();
	}

	auto pCout = cTotal / CPU_CLOCK_APPROX;

	std::cout << "\n\n\nLooping " << LOOPTIMES << " times:\n";
	std::cout << "\tprinf(): " << pPrintf << " sec\n";
	std::cout << "\tcout << ...: " << pCout << " sec\n";

	std::cin.get();
}

only the output is benchmarked. Both outputs are benchmarked in the same way, so you can rule out the time it takes to add integer to integer.

This still outputs printf(): 1 sec; cout << ...: 14 secs.

I wonder how many more arguments you will try to pop before finally saying you were wrong and C++ streams(that even the creators of them say that they are slow) are far slower than C's printf.

If you STILL dont believe me, take the code and compile it, you will see that the printf output goes into console order of magnitude faster than cout output
 
Status
Not open for further replies.
Top