views:

74

answers:

4

This is my program:

#include <stdio.h>
int main(int argc, char* argv[]) {
  char buf[1024] = {0};
  setvbuf(stdout, buf, _IOFBF, 1024);
  printf("error\n");
  printf("%s\n", buf);
}

And this is the output:

error
error

Exited: ExitFailure 7

Why are both lines 3 and line 4 blank lines ? Isn't the character '\n' flushing the output buffer and being discarded later?

+1  A: 

Your exit code tells me that printf printed 7 characters - I assume 5 in "error" and two more "\n"s. Could line 4 be added by your OS - by whatever prints "Exited"?

Arkadiy
+2  A: 

The call:

printf("error\n");

copies "error\n" into stdout's buffer, which is now buf, and then flushes that to the screen.

The call:

printf("%s\n", buf);

Then copies buf, which the previous printf call had set to "error\n" to buf again and appends another \n to it, so buf is now "error\n\n", so that's where your 2 blank lines come from.

Then since you did not return 0 at the end of main the return value from the last printf call was interpreted as the return value of main. Since "errno\n\n" is 7 characters long printf would have returned 7, and since that is not 0 it was interpreted as a failure by whoever ran the program.

nategoose
+2  A: 

You are certainly invoking undefined (or at least unspecified) behavior. You declare a buffer and then pass it via setvbuf to stdout. From that point on, the buffer is owned by stdout and not you anymore. That means you may not access it anymore. But this is exactly what you do.

I cannot prove it from the wording of the standard, but there sure is some combination of paragraphs that leads to my conclusion.

Update: ISO C99 says in 7.19.5.6p2 about the setvbuf function: The contents of the array at any time are indeterminate. So what you are seeing is just coincidence. You might also see anything else, there is no guarantee from ISO C99 alone.

Update 2: Because the contents of the array are indeterminate, they might as well all be non-null characters. And in that case, buf does not contain a string anymore. Therefore, you clearly invoke undefined behavior.

Roland Illig
A: 

The problem with your code is that you use one buffer for completely distinct tasks - using it as an intermediate output buffer and using its contents to print it to the output.

What your program does:

  1. Allocates a buffer `buf` and writes `'\0'` to `buf[0]` making it an empty string
  2. Sets the I/O buffer to `buf`
  3. Writes "error\n" to standard output - that means first to `buf` and then probably to the screen.
  4. `buf` now contains the string "error\n"
  5. You print contents of `buf` - that means `buf` gets copied to itself which might cause the weird exit failure later. This will print the second line containing error.

The extra \n characters are probably added by the system. Beware that \n does not flush the output buffer, you have to call the flushing function to be sure a flush has occurred.

dark_charlie
Hi, what do you mean by that \n does not flush the output buffer ? Do you mean that the contents of buf remain unchanged or are not flushed to screen. Thanks
Tracy
Actually it's both - \n doesn't force the text to appear on the screen. Only filling up the whole buffer or calling flush makes it appear on the screen. The contents of buf are implementation dependent but mostly the buf doesn't get zeroed when I/O is flushed, the next write after a flush will simply start writing from the beginning of buf.
dark_charlie
thanks,then what is i use cout<<endl ? Is that guaranteed to flush to screen ?
Tracy
@Tracy Yes, that is guaranteed to flush to screen.
dark_charlie