I'm writing a piece of code that needs to be on old K&R C style, and found a problem recently. When using no optimization I get one behaviour, with -O1 I get another, and with -O2 I get *yet another* behaviour. Both GCC and CLang show the same behaviour (although GCC shows three "versions" of the results, and CLang shows only two). There is probably something I did wrong in the code itself, I got the part of the program that showed the problem and placed it on a single test C file, which still showed the problem... although probably is some logic error of mine, the compiler shouldn't show different behaviours. The source code [test.c]: http://pastebin.com/SS1JHH1n The test file [test.psy]: http://pastebin.com/ejLqYaxH I'm not sure what is the problem over here, so I decided to report. :)
You should try your program e.g. under valgrind, or bother reading manual pages. One obvious bug is e.g. that you really can't call ungetc more than once without an intervening read from the stream.
And, even if ungetc works for more than one character (e.g. in glibc it will often work if you are calling ungetc with the characters that fgetc etc. returned from the stream, in reverse order, plus the one guaranteed unrelated ungetc), the /* If we were just checking ahead, unget everything */ while(j) { ungetc(buf[j], parser->file); j--; } loop is calling ungetc first with an uninitialized byte (j is one above the last index stored). There are various other issues in the program.
According to the man page here on Mac: Only one character of push-back is guaranteed, but as long as there is sufficient memory, an effectively infinite amount of push-back is allowed. And yeah, you are right (thank you!), that j was one byte ahead, but, still... shouldn't the behaviour be the same across optimization levels?
When you were calling ungetc with uninitialized char, that is invoking undefined behavior, anything can happen at that point.