3

There are may things in C which cause UB.

Most of them are ok to do so, but there are several ones where implementation-defined behaviour would be more logical. Let me have an example:

Concerning the << operator,

If E1 has a signed type and nonnegative value, and E1 × 2 E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

That means that

signed char r = 0x40;
r <<= 2;

is UB where IB would IMO be more logical.

Is an implementation allowed to define what happens here?

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • 4
    Well, undefined behavior means that the standard does not care what an implementation does. It may do something sensible. Or it may not. Both is fine with the standard. It may even do something sensible and tell its users about it, trying to lock their code into its platform. – cmaster - reinstate monica Jun 12 '14 at 07:47
  • @Dirk Thx, that's what I meant. Changed my Q. – glglgl Jun 12 '14 at 07:48
  • first time in my life I see undefined/implementation-defined behavior abbreviated as UB and IB! – Evert Jun 12 '14 at 07:57
  • @cmaster About "trying to lock their code into its platform", the same is the case with IB, isn't it? – glglgl Jun 12 '14 at 08:01
  • @Evert UB can be seen quite often; IB I didn't see not so often, but I think it is clear in this context. – glglgl Jun 12 '14 at 08:01
  • Yes. As with language extensions, which generally provide much stronger lock-in than certain implementation definition of UB and IB. – cmaster - reinstate monica Jun 12 '14 at 09:19
  • @glglgl: why is `signed char r = 0x40; r <<= 2;` undefined? –  Jun 12 '14 at 09:26
  • @dmcr_code I was under this impression after reading [this](http://stackoverflow.com/q/24178805/296974): "If E1 has a signed type and nonnegative value, and E1 × 2 ^ E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined." – glglgl Jun 12 '14 at 09:59

3 Answers3

2

From the C standard:

A conforming hosted implementation shall accept any strictly conforming program... A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program.

In other words, the implementation is free to guarantee a particular behavior for what would otherwise be undefined behavior. It just can't do it in a way which changes defined behavior.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • Ok, so the difference is: IB = the implementation *must* define the behaviour, UB = the implementation *may* define the behaviour. That sounds logical to me... – glglgl Jun 12 '14 at 07:49
  • 1
    But beware of these compiler _extensions_ that defines UB! There has been plenty of cases where the documented behavior changed from one compiler version to another, or with compiler options, sometimes in subtle ways. It is not too wise to rely on them. – rodrigo Jun 12 '14 at 07:50
2

The problem is:

signed char r = 0x40;
r <<= 2;

is not undefined behavior.

C says:

r <<= 2;

is equivalent to

r = r << 2;

with the only difference r is evaluated only once.

And r << 2 is equivalent to (int) r << 2 as with the << the integer promotions are applied on each operand.

So we actually have:

r <<= 2;

equivalent to

r = 0x100;

This assignment is also not undefined behavior. 0x100 is converted to signed char prior to the assignment and this conversion is ruled by c99, 6.3.1.3p3 which says the conversion here is implementation defined.

Now if it was undefined behavior the "implementor may augment the language by providing a definition of the officially undefined behavior" (from c99 Rationale document) (this is stated in c99, 4.p6).

ouah
  • 142,963
  • 15
  • 272
  • 331
  • I was under this impression after reading [this](http://stackoverflow.com/q/24178805/296974): "If E1 has a signed type and nonnegative value, and E1 × 2 ^ E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined." – glglgl Jun 12 '14 at 10:00
  • 1
    @glglgl yes but the *result type* in your quote is not `signed char` but `int` as (c99, 6.5.7p3) *"The type of the result is that of the promoted left operand"* – ouah Jun 12 '14 at 10:32
  • +1 for the excellent catch! Reading this answer made me realize an error in [my answer to a different question](http://stackoverflow.com/questions/7622/shift-operator-in-c/22734721#22734721), which I fixed, thanks! – legends2k Jun 13 '14 at 13:51
1

It's undefined behaviour in the sense that ISO C says so. If an implementation defines a specific behaviour for something (which is undefined in ISO C) then it's perfectly valid to do so. It's just not ISO C conformant one.

GCC has some extensions which are undefined in ISO C but valid in GNU C. E.g. Taking the size of a function/void (sizoof (a_function) and sizeof(void)).

The primary reason to follow ISO C is to make the code more portable. So if a behaviour is undefined for X (in ISO C) and your implementation defines a valid behaviour for X then your code is not portable other implementation(s) may not have anything defined for X.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • Well, it's important to qualify "conformant". An implementation can define an undefined behavior and still be an ISO C conformant implementation. It's the programs which rely on that behavior which are not conformant. – Sneftel Jun 12 '14 at 08:05
  • @Sneftel: Such programs are in many cases "conforming"--just not "strictly conforming". One major problem with published C Standards is that they define only two definitions of conformance, one of which is so loose as to be almost meaningless, and one of which is so restrictive that in many fields only a tiny fraction of C programs qualify or could practically be made to do so. – supercat Apr 21 '16 at 18:47