They say that when having UB, a program may do whatever it wants.
But if I have UB in one statement, such as
signed char a = 0x40;
a <<= 2;
or maybe even an unused(!) zero-size variable length array:
int l = 0;
char data[l];
is this in any way tolerable as only the result is undefined, or is this "bad" nevertheless?
I am especially interested in situations like these:
signed char a = 0x40;
a <<= 2;
switch (state) {
case X: return
case Y: do something with a; break;
case Z: do something else with a; break;
}
Assume that case X covers the case where the value of a
is undefined, and the other cases make use of this case. It would simplify things if I was allowed to calculate this the way I want and make the distinction later.
Another situation is the one I talked about the other day:
void send_stuff()
{
char data[4 * !!flag1 + 2 * !!flag2];
uint8_t cursor = 0;
if (flag1) {
// fill 4 bytes of data into &data[cursor]
cursor += 4;
}
if (flag2) {
// fill 2 bytes of data into &data[cursor]
cursor += 2;
}
for (int i=0; i < cursor; i++) {
send_byte(data[i])
}
}
If both flags are unset, I have the "undefined" array data
with length 0. But as I don't read from nor write to it, I don't see why and how it can possibly hurt...
In computer programming, undefined behavior (UB) is the result of executing a program whose behavior is prescribed to be unpredictable, in the language specification to which the computer code adheres.
So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended.
Undefined behavior exists mainly to give the compiler freedom to optimize. One thing it allows the compiler to do, for example, is to operate under the assumption that certain things can't happen (without having to first prove that they can't happen, which would often be very difficult or impossible).
Undefined Behavior results in unpredicted behavior of the entire program. But in unspecified behavior, the program makes choice at a particular junction and continue as usual like originally function executes.
Undefined behaviour means that it isn't defined by the C specification. It may very well be defined (or partially defined) for a specific compiler.
Most compilers define a behavior for unsigned shift.
Most compilers define whether zero-length arrays are allowed.
Sometimes you can change the bahaviour with compiler flags, like --pedantic
or flags that treat all warnings as errors.
So the answer to your question is:
That depends on the compiler. You need to check the documentation for your particular compiler.
Is it OK to rely on a specific result when you use something that is UB according to the C standard?
That depends on what you are coding. If it is code for a specific embedded system where the likelyhood of ever porting to anywhere else is low, then by all means, rely on UB if it gives a big return. But best practice is to avoid UB when possible.
Edit:
is this in any way tolerable as only the result is undefined, or is this "bad" nevertheless?
Yes (only the result is undefined is true in practice, but in theory, the compiler manufacturer can terminate the program without breaking the C spec) and yes, it is bad nevertheless (because it requires additional tests to ensure that the behaviour remains the same after a change is made).
If the behaviour is unspecified, then you can observe what behaviour you get. Best is if you check the assembly code generated.
You need to be aware that the behaviour can change if you change anything, though. Changes that may change the behaviour include, but is not limited to, changes to the optimization level, and the application of compiler upgrades or patches.
The people who write the compilers are generally rational people which means that in most cases the program will behave in the way that was easiest for the compiler developer.
Best practice is still to avoid UB when possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With