This is why the default-to-teach print in ziglang is std.debug.print -- this goes to stderr and the name implies you should yank them before cutting a release
That makes sense. For example, with curl, I have been redirecting the output from stderr to stdout with 2>&1 and grep to filter.
Now, I am seeing the dots connected why apps like curl sends the output to stderr!
In C++, I've absolutely had to explicitly use std::endl while debugging to make sure that my debug messages actually were visible when they were supposed to be. Using std::flush also works if you don't want to force a newline. However, in my experience, printing a newline character via std::cout does not flush the stream.
May not be the issue, but if you have your stdout piped into something or redirected to a file, you'll usually get a buffered stream, not a line-buffered one, in which case the \n won't trigger a flush.
Am I right to claim C compiler could determine the NULL pointer dereference is an undefined behavior and do anything, like completely removing the dereference?
At least the print and flush will occur before whatever the compiler decides to do with the UB, unless it's one of those purely-theoretical impelementations that can prove that those functions eventually return.
C compilers are allowed to assume that UB never happens. This means that if there is a code path that results in UB, the compiler can "know" that path will never be taken and simply not compile it (or replace it with code that summons demons through your serial port)
But if the compiler can prove that the code causing the UB will be reached regardless of the IO action, could it not assume that the IO action can never be reached, progagating the UB before it?
Correct, since unless the program is compiled with -nostdlib, the compiler can assume you're using its printf implementation which does not alter code flow (such as by exit(), longjmp, or exceptions in C++)
That's still irrelevant. The compiler can look at any code like this:
```
invokeUB();
doSomething();
```
and regardless of what `doSomething()` does (it need not be a function call), remove the call entirely if it so chooses. The reason for this is that `doSomething()` cannot be reached except after `invokeUB()`. Because undefined behaviour can be considered unreachable, `invokeUB()` can be too. Therefore, to the compiler, it is impossible to ever reach `doSomething()`, and thus it may be safely eliminated.
In practical terms, compilers are allowed to reorder calculations, and the print might as well not be there if it's after a crash.
In theoretical terms, once UB is guaranteed to happen then your program execution is no longer valid, the entire execution, and the compiler is not bound by any rules whatsoever.
Not the compiler. We don't always know if a reference is null at compile time. Especially if we have hardware that can make references invalid when they otherwise might not be.
You can also unbuffer stdout in a wrapper then exec your program. GNU-ish systems, including Linux, usually include a command called stdbuf that does this:
stdbuf -i0 -o0 -e0 /some/command
Where -i is for stdin, -o is for stdout, and -e is for stderr, and the number is the buffer size.