Value of uninitialized variable

  • Thread starter Philipp Klaus Krause
  • Start date
P

Philipp Klaus Krause

What's the value of an uninitialized variable?

E.g. for a bool, is it always true or false? For an int is it an integer
value in [INT_MIN, INT_MAX]?

Philipp
 
N

Nick Keighley

What's the value of an uninitialized variable?

assuming you're talking about automatic variables (see Richard's post)
then the value is undefined. The standard allows "trap values" and
attempts to read a trap value will cause the program to fail.
E.g. for a bool, is it always true or false?
no.

For an int is it an integer value in [INT_MIN, INT_MAX]?

no

but if it makes you any happier unsigned char is an exception in that
it cannot be a trap value. I'm guessing that all bit patterns are
hence valid values.
 
E

Ersek, Laszlo

assuming you're talking about automatic variables (see Richard's post)
then the value is undefined. The standard allows "trap values" and
attempts to read a trap value will cause the program to fail.

The derivation seems to be:


C99 6.7.8 Initialization, p10: "If an object that has automatic storage
duration is not initialized explicitly, its value is indeterminate."

C99 3.17.2 "indeterminate value: either an unspecified value or a trap
representation"

C99 6.2.6 Representations of types / 6.2.6.1 General, p5

"Certain object representations need not represent a value of the object
type. If the stored value of an object has such a representation and is
read by an lvalue expression that does not have character type, the
behavior is undefined. If such a representation is produced by a side
effect that modifies all or any part of the object by an lvalue
expression that does not have character type, the behavior is undefined.
41) Such a representation is called a trap representation."

Footnote 41:

"Thus, an automatic variable can be initialized to a trap representation
without causing undefined behavior, but the value of the variable cannot
be used until a proper value is stored in it."


For C90, the path is a bit different:

C90 6.5.7 Initialization

"If an object that has automatic storage duration is not initialized
explicitly, its value is indetelminate."

C90 3.16 "undefined behavior: Behavior, upon use of [...] indeterminately
valued objects, for which this International Standard imposes no
requirements."

I'm not sure if in C90 an access with character type is exempted like in
C99.

Cheers,
lacos
 
S

Seebs

What's the value of an uninitialized variable?
Unspecified.

E.g. for a bool, is it always true or false? For an int is it an integer
value in [INT_MIN, INT_MAX]?

For anything but unsigned char, it may be a trap representation, which is
to say, accessing the value can cause undefined behavior.

(Actually, I'm not sure about bool.)

-s
 
E

Eric Sosman

[...]
Usually, the value of an automatic variable, unless it is a pointer and
you dereference it, is something that is simply a pseudo-random data
value and it won't do any harm to simply access the value or output it
using printf(). The reason for this is that in any machine
representation, typically all possible bit patterns mean SOMETHING.

One such SOMETHING is "signalling NaN," for most systems.
[...]
I believe that some coding standards require initializers on all
automatics. The cost in extra code may be justified by the reduction in
the probability of a certain class of bug.

There may well be such standards. IMHO they are wrong-
headed, ill-advised, counter-productive, and in poor taste.
Compilers and lints can do enough analysis to tell whether a
path exists that might cause a variable to be read before it
is written, and will issue warning messages if such paths
are found. But if the variable is initialized the diagnostics
are suppressed, and all you get is a wrong answer at run-time.
A reproducible wrong answer, yes, and that's helpful in finding
the bug -- but it's less helpful than having the bug pointed
out to you at compile time.
 
T

Tim Rentsch

Nick Keighley said:
What's the value of an uninitialized variable?

assuming you're talking about automatic variables (see Richard's post)
then the value is undefined. The standard allows "trap values" and
attempts to read a trap value will cause the program to fail.
E.g. for a bool, is it always true or false?
no.

For an int is it an integer value in [INT_MIN, INT_MAX]?

no

but if it makes you any happier unsigned char is an exception in that
it cannot be a trap value. I'm guessing that all bit patterns are
hence valid values.

Under C1X, even unsigned chars can cause traps if unitialized.
(And there are even real machines that do, which is why the
behavior was changed.)
 
B

Ben Bacarisse

Seebs said:
What's the value of an uninitialized variable?
Unspecified.

E.g. for a bool, is it always true or false? For an int is it an integer
value in [INT_MIN, INT_MAX]?

For anything but unsigned char, it may be a trap representation, which is
to say, accessing the value can cause undefined behavior.

(Actually, I'm not sure about bool.)

I can't see any wording that might exempt _Bool from having trap
reps. That's not a proof, of course, but where do your doubts come
from?
 
S

Seebs

I can't see any wording that might exempt _Bool from having trap
reps. That's not a proof, of course, but where do your doubts come
from?

Imagine if you will a _Bool bitfield (I *think* those got officially
tacked on at some point?) with only one bit. We know it holds two
values. We know it has two valid values. I don't think it can have
a trap representation.

In practice, though, I don't see any guarantees, and a non-bitfield
_Bool could presumably have as a trap representation "anything but 0 or
1". Thus, if you assigned 23 to it, the compiler would generate code
to change that silently to a 1 (because true is always exactly 1),
but if you memcpy'd 23 over it, it would be a trap representation.

This would most likely require extra code to set up in the compiler, but
it might be sorta cool. Certainly, it would lead to another generation of
insanely complicated #defines for "true".

-s
 
B

Ben Bacarisse

Seebs said:
Imagine if you will a _Bool bitfield (I *think* those got officially
tacked on at some point?) with only one bit. We know it holds two
values. We know it has two valid values. I don't think it can have
a trap representation.

I am getting lost. That's an argument that bools with only one bit
can't have trap reps. I agree. You seemed unwilling to assert that
bool can have trap reps. Maybe I miss-understood your "I am not sure
about bool". You've snipped it, so the context is getting lost.
In practice, though, I don't see any guarantees, and a non-bitfield
_Bool could presumably have as a trap representation "anything but 0 or
1". Thus, if you assigned 23 to it, the compiler would generate code
to change that silently to a 1 (because true is always exactly 1),
but if you memcpy'd 23 over it, it would be a trap representation.

Yes, this seems eminently possible. I thought you were not sure that
this was possible.

<snip>
 
S

Seebs

Yes, this seems eminently possible. I thought you were not sure that
this was possible.

I'm not. There could be something I haven't thought of that prevents _Bool
from being allowed to have a trap representation.

-s
 
T

Tim Rentsch

Seebs said:
I'm not. There could be something I haven't thought of that prevents _Bool
from being allowed to have a trap representation.

A regular _Bool can be a trap representation. A _Bool bitfield
cannot be a trap representation, even if the bitfield has a width
greater than one, which apparently is allowed.
 
B

Ben Bacarisse

Tim Rentsch said:
A regular _Bool can be a trap representation. A _Bool bitfield
cannot be a trap representation, even if the bitfield has a width
greater than one, which apparently is allowed.

That's interesting. I can't see why a _Bool bit-field would be
different from a normal _Bool object. What is the reasoning?
 
T

Tim Rentsch

Ben Bacarisse said:
That's interesting. I can't see why a _Bool bit-field would be
different from a normal _Bool object. What is the reasoning?

A bit-field is interpreted as a signed or unsigned integer type
consisting of the specified number of bits. (6.7.2.1p9)

Values stored in unsigned bit-fields and objects of type unsigned
char shall be represented using a pure binary notation. (6.2.6.1p3)

(For unsigned integer types) If there are N value bits, each bit
shall represent a different power of 2 between 1 and 2**(N-1), so
that objects of that type shall be capable of representing values
from 0 to (2**N)-1 using a pure binary representation. (6.2.6.2p1)

The type _Bool is an unsigned integer type. (6.2.5p6)


I admit, it seems strange that a _Bool bitfield might be required to
represent values other than 0 and 1, but apparently that's true if
an implementation admits a _Bool bitfield of width greater than one
(which I think is allowed but not required). Maybe <limits.h>
should have a new entry, BOOL_MAX, for the maximum value that can be
represented in a _Bool bitfield. How scary is that?
 
B

Ben Bacarisse

Tim Rentsch said:
A bit-field is interpreted as a signed or unsigned integer type
consisting of the specified number of bits. (6.7.2.1p9)

Values stored in unsigned bit-fields and objects of type unsigned
char shall be represented using a pure binary notation. (6.2.6.1p3)

This is the part I was missing. Thanks.
(For unsigned integer types) If there are N value bits, each bit
shall represent a different power of 2 between 1 and 2**(N-1), so
that objects of that type shall be capable of representing values
from 0 to (2**N)-1 using a pure binary representation. (6.2.6.2p1)

The type _Bool is an unsigned integer type. (6.2.5p6)


I admit, it seems strange that a _Bool bitfield might be required to
represent values other than 0 and 1, but apparently that's true if
an implementation admits a _Bool bitfield of width greater than one
(which I think is allowed but not required). Maybe <limits.h>
should have a new entry, BOOL_MAX, for the maximum value that can be
represented in a _Bool bitfield. How scary is that?

I think we need it for non-bit-field _Bool objects as well! If a _Bool
bit-field has a width > 1 it means that plain _Bool has a width > 1;
i.e. that is has more than 1 value bit.

Because of 6.3.1.2 p1, the only way to get such a value into it is by
byte copying, but once there the value must come out. Of course, an
implementation may mandate that the width of _Bool is 1 (with the rest
of the bit being padding bits) but then _Bool bit-fields as also
limited to a with of 1.

gcc, for one, seems to give _Bool CHAR_BIT value bits. The effect is
that, given an object b of type_Bool, the expressions b and (_Bool)b
need not have the same value. Is _Bool the only type with this
property?
 
K

Keith Thompson

Ben Bacarisse said:
gcc, for one, seems to give _Bool CHAR_BIT value bits. The effect is
that, given an object b of type_Bool, the expressions b and (_Bool)b
need not have the same value. Is _Bool the only type with this
property?

As of gcc 4.3.3, sizeof (_Bool) is 1, but it appears that only one of
the 8 bits is a value bit.

If I try to declare a bool bit field wider than one bit, I get:

error: width of 'b2' exceeds its type

As for b vs. (_Bool)b, an experiment indicates that they yield the
same result:

#include <stdio.h>

int main(void)
{
printf("sizeof (_Bool) = %zu\n", sizeof (_Bool));
_Bool b_two;
*(char*)&b_two = 2;
char c_two = 2;
printf("b_two = %d, (_Bool)b_two = %d\n", b_two, (_Bool)b_two);
printf("c_two = %d, (_Bool)c_two = %d\n", c_two, (_Bool)c_two);
return 0;
}

Output:

sizeof (_Bool) = 1
b_two = 2, (_Bool)b_two = 2
c_two = 2, (_Bool)c_two = 1

Hypothesis: _Bool has 1 value bit and 7 padding bits, and any
representation where any of the padding bits are 1 is a trap
representation. This means that any attempt to access the value
of b_two invokes undefined behavior -- even a cast to _Bool; the
compiler assumes that the stored value must be either 0 or 1, so
it doesn't need to normalize any non-zero value to 1, as it does
for types other than _Bool.
 
B

Ben Bacarisse

Keith Thompson said:
As of gcc 4.3.3, sizeof (_Bool) is 1, but it appears that only one of
the 8 bits is a value bit.

If I try to declare a bool bit field wider than one bit, I get:

error: width of 'b2' exceeds its type

As for b vs. (_Bool)b, an experiment indicates that they yield the
same result:

#include <stdio.h>

int main(void)
{
printf("sizeof (_Bool) = %zu\n", sizeof (_Bool));
_Bool b_two;
*(char*)&b_two = 2;
char c_two = 2;
printf("b_two = %d, (_Bool)b_two = %d\n", b_two, (_Bool)b_two);
printf("c_two = %d, (_Bool)c_two = %d\n", c_two, (_Bool)c_two);
return 0;
}

Output:

sizeof (_Bool) = 1
b_two = 2, (_Bool)b_two = 2
c_two = 2, (_Bool)c_two = 1

Hypothesis: _Bool has 1 value bit and 7 padding bits, and any
representation where any of the padding bits are 1 is a trap
representation. This means that any attempt to access the value
of b_two invokes undefined behavior -- even a cast to _Bool; the
compiler assumes that the stored value must be either 0 or 1, so
it doesn't need to normalize any non-zero value to 1, as it does
for types other than _Bool.

Perfectly possible. I don't think it is easy to tell if this is the
case of not. An implementation need not support bit-fields wider than
1 for _Bool even if _Bool has more than 1 value bit, so I can't (off
hand) think of a way to tell if your or my hypothesis is correct.

(I am being a bit glib -- I prefer yours as an explanation -- but I
really don't know how to tell. Should not some aspect of this be
implementation defined so as to ensure it is documented?)
 
T

Tim Rentsch

Ben Bacarisse said:
This is the part I was missing. Thanks.


I think we need it for non-bit-field _Bool objects as well! If a _Bool
bit-field has a width > 1 it means that plain _Bool has a width > 1;
i.e. that is has more than 1 value bit.

I see your point. Actually an implementation could define
the width of plain _Bool to be 1 but still allow _Bool bitfields
of width > 1, but being a constraint violation a diagnostic would
be required. (That doesn't take away from your point, which is
a good one.)
Because of 6.3.1.2 p1, the only way to get such a value into it is by
byte copying,

.... or by using unions ...
but once there the value must come out. Of course, an
implementation may mandate that the width of _Bool is 1 (with the rest
of the bit being padding bits) but then _Bool bit-fields as also
limited to a with of 1.

Again, wider _Bool bitfields could still be allowed as long as
a diagnostic is given.
gcc, for one, seems to give _Bool CHAR_BIT value bits. The effect is
that, given an object b of type_Bool, the expressions b and (_Bool)b
need not have the same value. Is _Bool the only type with this
property?

I believe the floating-point types also can exhibit this behavior
(ie, and still be conforming).
 
T

Tim Rentsch

Keith Thompson said:
As of gcc 4.3.3, sizeof (_Bool) is 1, but it appears that only one of
the 8 bits is a value bit.

If I try to declare a bool bit field wider than one bit, I get:

error: width of 'b2' exceeds its type

To to report: I got a different result in an earlier version of gcc
(don't remember which one offhand) -- _Bool bitfields were allowed up
to a width of 8 (and CHAR_BIT was also 8).
As for b vs. (_Bool)b, an experiment indicates that they yield the
same result:

#include <stdio.h>

int main(void)
{
printf("sizeof (_Bool) = %zu\n", sizeof (_Bool));
_Bool b_two;
*(char*)&b_two = 2;
char c_two = 2;
printf("b_two = %d, (_Bool)b_two = %d\n", b_two, (_Bool)b_two);
printf("c_two = %d, (_Bool)c_two = %d\n", c_two, (_Bool)c_two);
return 0;
}

Output:

sizeof (_Bool) = 1
b_two = 2, (_Bool)b_two = 2
c_two = 2, (_Bool)c_two = 1

This could be the result of undefined behavior, but it weren't (ie,
because the width of _Bool were greater than 1) the expressions b_two
and (_Bool) b_two still should yield the same result, because of the
rule that converting to the same type as the operand type causes no
change to the value or the representation.
Hypothesis: _Bool has 1 value bit and 7 padding bits, and any
representation where any of the padding bits are 1 is a trap
representation.

Presumably that's true in this implementation; certainly it
could be true (in this implementation). But it doesn't have to
be true in other implementations.
This means that any attempt to access the value
of b_two invokes undefined behavior -- even a cast to _Bool; the
compiler assumes that the stored value must be either 0 or 1, so
it doesn't need to normalize any non-zero value to 1, as it does
for types other than _Bool.

Again, in this implementation. In another implementation, where
the width of _Bool is CHAR_BIT (and where sizeof (_Bool) == 1),
the behavior would be defined -- implementation-specific, to be
sure, but necessarily defined in that implementation.
 
T

Tim Rentsch

Ben Bacarisse said:
Perfectly possible. I don't think it is easy to tell if this is the
case of not. An implementation need not support bit-fields wider than
1 for _Bool even if _Bool has more than 1 value bit,

I don't know where you're getting this. My reading is that, if the
width of _Bool is N > 1, then programs are allowed to use _Bool
bitfields of width up to N, and therefore implementations are
required to support them. (The quantity N may be any value between
1 and CHAR_BIT.) So if an implementation doesn't accept _Bool
bitfields of width > 1, I don't see how it's possible for the width
of _Bool in that implementation to be anything other than 1.

[And therefore, to complete Keith's argument, the only way to get a
value other than 0 or 1 out of a _Bool variable, with _Bool having a
width of 1, is for (at least some of) the padding bits to produce trap
representations.]
so I can't (off
hand) think of a way to tell if your or my hypothesis is correct.

(I am being a bit glib -- I prefer yours as an explanation -- but I
really don't know how to tell. Should not some aspect of this be
implementation defined so as to ensure it is documented?)

Absolutely. Even if (as I think it is) it is possible to tell the
width of _Bool by the width of _Bool bitfields that an implementation
accepts, either the width of _Bool, or BOOL_MAX, or something similar,
should still be implmentation-defined. Then if the width of _Bool
were anything less than sizeof (_Bool) * CHAR_BIT, the possibility
of trap representations could be inferred.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top