2

The code below:

_Bool field0;
char field1;

printf("fieldX:                [%d]\t[%d]\n", field0,         field1);
printf("fieldX ? 1 : 0:        [%d]\t[%d]\n", field0 ? 1 : 0, field1 ? 1 : 0);
printf("!fieldX:               [%d]\t[%d]\n", !field0,        !field1);
printf("!!fieldX:              [%d]\t[%d]\n", !!field0,       !!field1);

Gives the following output:

fieldX:                [165]  [165]
fieldX ? 1 : 0:        [165]  [1]
!fieldX:               [164]  [0]
!!fieldX:              [165]  [1]

Looks quite surprising, especially ternary operator result.

Checked with gcc 4.9.3 and 4.8.3, -O0, no -flto.

Remark: the stack was previously initialized with 0xa5 pattern (embedded C environment).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    Accessing an object with automatic storage invokes undefined behavior. Nothing strange here. – ouah Nov 28 '16 at 19:56
  • 3
    @ouah - do you miss a `uninitialized` in that comment? – Support Ukraine Nov 28 '16 at 19:59
  • Possible duplicate of [Does "Undefined Behavior" really permit \*anything\* to happen?](http://stackoverflow.com/questions/32132574/does-undefined-behavior-really-permit-anything-to-happen) – kaylum Nov 28 '16 at 20:01
  • 1
    Perhaps the compiler knows that an initialized `_Bool` can only have value `0` or `1`, so it optimizes `field0 ? 1 : 0` to `field0` – M.M Nov 28 '16 at 20:03
  • @4386427 thanks for noticing. Unfortunately, I'm no longer allowed to edit and add the missing word. – ouah Nov 28 '16 at 20:04
  • @M.M yes, totally makes sense. The code above is actually a simplified one, the real code tried to check that multiple struct _Bool fields were properly mutually exclusively initialized (namely, in [Protobuf Union structure](https://developers.google.com/protocol-buffers/docs/techniques#union)). Actually, from now on, I'd like to avoid using _Bool whenever possible. Maybe that's not very professional -- but if I have used to use chars, ints etc that acted certain similar way, what for should I increase the possibility to shoot myself in my leg, right? – Oleg Tcaregorodtcev Nov 28 '16 at 22:40
  • @OlegTcaregorodtcev to avoid problems, don't use uninitialized variables. You should not rely on behaviour of uninitialized `char` or anything else either. It is not possible to test if something is uninitialized, it's the responsibility of the calling code to not declare uninitialized variables and pass them around. – M.M Nov 28 '16 at 22:45
  • @M.M totally agree with you, in fact, gcc will emit a compile-time warning upon an uninitialized local variable (-Wall -Wextra). But I was unable to find how to make it emitting the same warning for uninitialized struct field. I was writing a function that would be like EncodeAndSendProtobuf(PB_Struct *s). And it'd be great to implement something like checking contracts (I hope I got the concept right). I see nothing wrong with "fail fast" principle. So I'm not relying on the undefined behaviour here to convey some "production-grade" data, but rather to use it to conduct additional checks. – Oleg Tcaregorodtcev Nov 28 '16 at 22:58
  • Some people recommend always initializing every variable declaration. (the compiler will optimize it out if the value is always overwritten before first use) – M.M Nov 28 '16 at 23:03
  • That's a good strategy to employ. But the reality is that I myself almost always work in teams, and we are all people, so... I'd like to write modules/functions in a way so that they treat their input as unreliable. The more checks -- the better. – Oleg Tcaregorodtcev Nov 28 '16 at 23:14

2 Answers2

1

Accessing an uninitialized automatic variable causes undefined behaviour in most cases, in this one.

See this thread for the exact details of "most".

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
1

Accessing an uninitialized object with automatic storage invokes undefined behavior. So nothing strange here.

Moreover a _Bool object can only hold two values: either 0 or 1. An implementation is allowed to replace !!boolean_object or boolean_object ? 1 : 0 by boolean_object.

(Also note that even with -O0, gcc is still performing some optimizations: for example, it inlines static functions called once.)

ouah
  • 142,963
  • 15
  • 272
  • 331