+ 17
Position of output of system() in C/C++
While fiddling around with with sololearn's command processor via the system() function in c/c++, I observed the following things : - output from system function is positioned either at the very top or at very bottom of the output file, and doesn't depend on the the output from the program ( via std::cout or printf() ). - this behaviour is command depended and not depend on where/when the function is called. - it is not a sololearn specific behaviour, same happens with a lot of other online server based IDE's also (like one of codechef). can someone enlighten me about what is going on here ? Here is the code 👇 https://code.sololearn.com/ce2E6cP9P741/?ref=app
17 Respuestas
+ 13
Can it be that gcc --version outputs to stderr and gcc --v to stdout, and then sololearn just concatenates stderr and stdout?
This test seems to support it:
https://code.sololearn.com/cpx12ojjY6hj/?ref=app
Edit: like Arsenic noticed it is the other way round: "gcc -v" writes to stderr, and "gcc --version" to stdout
+ 7
In the last case the output of the program is piped through a second process, an instance of `more`. The `system` call also creates a process. Apparently (but it's just a hypothesis) `more` buffers the input it receives instead of presenting each line right away.
+ 6
we know that std cout is ostream object..using just << doesnt mean it will output it to screen..it just stores in buffer..then you have to flush it explicitly using std::flush, or just use std::endl (implicitly flushed).
idk about the system function though.
+ 6
Volodymyr Chelnokov I think you mean "gcc --version" to stdout and "gcc -v" to stderr.
If so, then that makes a whole lot of sense , as it is a fact that sololearn's code playground and other online IDEs that I used, merges stdout and stderr at the end (you can look at the attached code to have a look at bashfile which soloearn uses to run the code as a proof)
And from your code , I am pretty convinced that "gcc -v" outputs in stderr stream. ( Why it is doing so is still a mystery )
https://code.sololearn.com/cQM7WC5FCfbA/?ref=app
+ 6
/*Using fedora here, and the code you posted works fine. thats why you dont use system()
[~]
$ cat test.cpp*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf( "One\n" );
system( "echo two" );
printf( "Three\n" );
}
/*
[~]
$ g++ test.cpp
[~]
$ ./a.out
One
two
Three
[~]
$ ./a.out | more
two
One
Three
*/
+ 4
Arsenic [Part 1]
Just a disclaimer. What I say might be insanely dumb because it is just a wild guess. Just saying this because it sounds kinda dumb to me, but it's the best solution I could come up with.
So, I tried running 'gcc -v' on Termux (if you don't know, a Linux emulator on Android), and there was a *slight* delay between running the command and getting the output. I couldn't try with 'gcc —version' because gcc is basically an alias for clang in termux and 'gcc -v' and 'gcc —version' give the same result.
But, if we take the delay into consideration and *assume*, that 'gcc —version' has a much smaller delay than 'gcc -v', then I think the execution of your code works like this
1. It makes a call to the system to execute 'gcc —version', which immediately appends output to the stdout
2. Then, it makes a call to 'gcc -v'. Now all your program does is make a call to the system and move on.
3. It encounters the cout statement and appends to the stdout
+ 4
[Part 2]
4. Encounters another 'gcc —version', same as point 1
5. Another 'gcc -v', same as point 2
6. Another cout statement, same as point 3
7. By this time, the first 'gcc -v' is completed and now that appends to the stdout
8. By this time, the second 'gcc -v' finishes and does the same thing
Now, I know system() is blocking. So here comes the dumb part which is my *assumption* that online platforms **fork** processes. So when you execute 'gcc -v', instead of simply executing the process, SoloLearn forks the process which makes it run alongside the execution of the main program.
Thus, because 'gcc —version' takes negligible time to complete, its effect is seen as expected and because 'gcc -v' takes more time, its execution finishes after all other processes and the effect is seen at the end (or possibly, after the execution of the program).
+ 4
I answered without reading other answers. It's really strange why gcc -v and gcc --version output to stderr and stdout.
+ 4
This way, you can preserve the output order.
https://code.sololearn.com/c0VxdwJCsjQL/?ref=app
+ 4
💫💫 does the wrong order remain if you do fflush(stdout) after each printf?
+ 3
Lily Mea yes that make sense.
But even after flushing the buffer before printing system() calls, the output from one command is fixed, but behaviour of other one is still unexplained 👇
https://code.sololearn.com/cO9C3y8oBWZJ/?ref=app
I suspect this has something to do with child process( created by system() ) inheriting the buffer of parent process
+ 3
XXX the assumption is correct for both online and ofline platform. This is how system() roughly works :-
1) fork the process ( using fork() )
2) execute the command in that process ( using execl() )
And now it's starting to come together. 🙂
The fork process finishes the call to "gcc --version" much faster and push the output to stout but as Lily Mea said, cout was loading it in buffer, waiting for buffer to flush or be filled. That's why when I used "endl" to flush it, the first statement appeared before the second call to "gcc --version", meanwhile "gcc -v" is going on slowly in the background making the output display at the end.
Thanks both of you for your answers
+ 3
Arsenic
One thing I don't understand. You said that system() does the same thing in both online platforms and on offline systems, i.e., fork() and execl(). So if the process is forked in both cases, how is system() on offline systems blocking while on online platforms, it is not?
+ 3
By adding endl at the end of the cout (as opposed to or in addition to '\n') you can get cout to immediately flush the buffer and thereby preserve the order of output like so:
https://code.sololearn.com/c4ljgba95JVA/?ref=app
+ 3
By adding "2 >&1" at the end of "gcc -v" you can redirect the gcc output to go to stdout.
+ 3
💫💫 that's most probably because by default interactive terminals are line buffered means the output is flushed at the end of every line while this doesn't happen when it is piped ( where stream is fully buffered )
Try to flush the buffer before calling the system() (as suggested by Volodymyr Chelnokov ) and check what happens.