Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Undefined behaviour" in a statement?

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...

like image 517
glglgl Avatar asked Jun 12 '14 07:06

glglgl


People also ask

What is undefined behavior in programming?

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.

What does undefined behavior mean in C?

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.

Why does undefined behavior exist?

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).

What is the difference between unspecified and undefined?

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.


1 Answers

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.

like image 198
Klas Lindbäck Avatar answered Oct 10 '22 10:10

Klas Lindbäck