views:

489

answers:

4

I've seen the terms "IB" and "UB" used several times, particularly in the context of C++. I've tried googling them, but apparently those two-letter combinations see a lot of use. :P

So, i ask you...what do they mean, if they're said like it's a bad thing?

+2  A: 

UB: Undefined Behavior

IB: Implementaion-defined Behavior

missingfaktor
So IB is... Integrated Barometer? :P
FrustratedWithFormsDesigner
@Frustrated: Wasn't sure about IB. Had to Google for it. :P
missingfaktor
+15  A: 

IB: Implementation-defined behaviour. The standard leaves it up to the particular compiler/platform to define the precise behaviour, but requires that it be defined.

Using implementation-defined behaviour can be useful, but makes your code less portable.

UB: Undefined behaviour. The standard does not specify how a program invoking undefined behaviour should behave. Also known as "nasal demons" because theoretically it could make demons fly out of your nose.

Using undefined behaviour is nearly always a bad idea. Even if it seems to work sometimes, any change to environment, compiler or platform can randomly break your code.

Thomas
I'm still waiting for a demon flying out of someone's nose because of using undefined behaviour in C++. I guess it will happen when the first compilers fully comply with the new C++ standard.
OregonGhost
+1 for "nasal demons". :)
cHao
@OregonGhost: I guess you're right. I've seen it happen with unicorns a couple times, but never demons.
Thomas
@Thomas: I'd accept Unicorns as well. Doesn't matter if one horn or two horns, like many demons have.
OregonGhost
@OregonGhost - the standard does not specify how many horns a demon should have.
DVK
I've always hated the 'nasal demons' example of undefined behavior. Can't someone come up with a more entertaining yet less goofy allegory (or metaphor or simile or whatever the 'nasal demons' thing is)?
Michael Burr
Well, interrupting the service because a 2GB memory dump is being written to the disk which considerably slow things down is not goofy enough I am afraid :(
Matthieu M.
@Michael Burr: I prefer "catch fire". It's evidently catastrophic, and it has at least a vague air of plausibility (computer hardware does sometimes catch fire, admittedly for reasons of hardware rather than software failure in the case of any system you'd be reading this thread on).
Steve Jessop
+4  A: 
  • IB: is implementation defined behavior - the compiler must document what it does. Performing a >> operation on a negative value is an example.

  • UB: undefined behavior - the compiler can do what ever, including simply crashing or giving unpredictable results. Dereferencing a null pointer falls into this category, but also subtler things like pointer arithmetic that falls outside the bounds of an array object.

Another related term is 'unspecified behavior'. This is kind of between implementation defined and undefined behaviors. for unspecified behavior, the compiler must do something according to the standard, but exactly which choices the standard gives it is up to the compiler and need not be defined (or even consistent). Things like order of evaluation of sub-expressions falls in this category. The compiler can perform these in whatever order it likes, and could do it differently in different builds or even in different runs of the same build (unlikely, but permitted).

Michael Burr
+4  A: 

Implementation-defined behavior and Undefined behavior

The C++ standard is very specific about the effects of various constructs, and in particular you should always be aware of these categories of trouble:

  • Undefined behavior means that there are absolutely no guarantees given. The code could work, or it could set fire to your harddrive or make demons fly out your nose. As far as the C++ language is concerned, absolutely anything might happen. In practical terms, this generally means that you have an unrecoverable bug. If this happens, you can't really trust anything about your application (because one of the effects of this undefined behavior might just have been to mess up the memory used by the rest of your app). It's not even required to be consistent, so simply running the program twice might give different results. It may depend on the phases of the moon, the color of the shirt you're wearing or absolutely anything else.
  • Unspecified behavior means that the program must do something sane and consistent, but it is not required to document this.
  • Implementation-defined behavior is similar to unspecified, but must also be documented by the compiler writers. An example of this is the result of a reinterpret_cast. usually, it simply changes the type of a pointer, without modifying the address, but the mapping is actually implementation-defined, so a compiler could map to a completely different address, as long as it documented this choice. Another example is the size of an int. The C++ standard doesn't care if it is 2, 4 or 8 bytes, but it must be documented by the compiler

But common for all of these is that they're best avoided. When possible, stick with behavior that is 100% specified by the C++ standard itself. That way, you're guaranteed portability.

You often have to rely on some implementation-defined behavior as well. It may be unavoidable, but you should still pay attention to it, and be aware that you're relying on something that may change between different compilers.

Undefined behavior, on the other hand, should always be avoided. In general, you should just assume that it makes your program explode in one way or another.

jalf
UB should be avoided *if you care about portability*. A particular implementation can define what happens for specific undefined behavior, and in some cases (especially device drivers and smaller embedded systems) you need to use those things.
Jerry Coffin
@Jerry: No, UB should be avoided *if it is entirely undefined*. If the platform/implementation/runtime/compiler gives further guarantees, then you can rely on the behavior and lose portability. But then it's no longer quite as undefined... Most of the time, though, you have no such guarantees, and undefined is just undefined, and should be avoided at all costs.
jalf
"consistent" might be a misleading description of unspecified behavior. It has to be consistent with the general context of the operation, for example if an expression has "unspecified value" then the result must *be* a value, if you store it then the stored value must thereafter compare equal to itself, and so on. But unspecified results need not be consistent over time (same output for same input if you run it again), or even deterministic.
Steve Jessop
"no longer quite as undefined" - it's exactly as undefined *by the standard*, and UB is a short-hand meaning undefined by the standard. In your example it's defined by the implementation. For that matter you could rely on behaviour that isn't defined by the standard *or* the implementation, if you've checked the object code and don't plan to recompile ever again ;-)
Steve Jessop
"must thereafter compare equal to itself". Hmm, unless it's a NaN. Anyway, it must have whatever behavior is required of its type.
Steve Jessop