M
Malcolm McLean
You use some weird and wonderful architectures.Incidentally, sizeof(int)==1 isn't needed, only INT_MAX < UCHAR_MAX
(which is possible even if sizeof(int) > 1).
You use some weird and wonderful architectures.Incidentally, sizeof(int)==1 isn't needed, only INT_MAX < UCHAR_MAX
(which is possible even if sizeof(int) > 1).
Tim Rentsch said:Peter Nilsson said:Jens said:Use int as a replacement type for _Bool, since any expression
where you use _Bool that expects an integer type will promote
_Bool to int, anyhow.
_Bool is an unsigned type.
right, but you will not notice this much.
I don't with a real _Bool, I do with a standin bool.
In any kind of arithmetic or comparison it will always be
promoted to an int since the two legal values of _Bool
always fit into and int.
To nitpick, C99 does not say that 0 and 1 are the only legal
values for bool, [snip elaboration]
Not said explicitly, but this does hold as a logical consequence
of the rules governing conversions.
Ben Bacarisse said:Tim Rentsch said:Peter Nilsson said:Use int as a replacement type for _Bool, since any expression
where you use _Bool that expects an integer type will promote
_Bool to int, anyhow.
_Bool is an unsigned type.
right, but you will not notice this much.
I don't with a real _Bool, I do with a standin bool.
In any kind of arithmetic or comparison it will always be
promoted to an int since the two legal values of _Bool
always fit into and int.
To nitpick, C99 does not say that 0 and 1 are the only legal
values for bool, [snip elaboration]
Not said explicitly, but this does hold as a logical consequence
of the rules governing conversions.
But there are other ways to get a value into a _Bool than via a
conversion.
Tim Rentsch said:Ben Bacarisse said:Tim Rentsch said:Use int as a replacement type for _Bool, since any expression
where you use _Bool that expects an integer type will promote
_Bool to int, anyhow.
_Bool is an unsigned type.
right, but you will not notice this much.
I don't with a real _Bool, I do with a standin bool.
In any kind of arithmetic or comparison it will always be
promoted to an int since the two legal values of _Bool
always fit into and int.
To nitpick, C99 does not say that 0 and 1 are the only legal
values for bool, [snip elaboration]
Not said explicitly, but this does hold as a logical consequence
of the rules governing conversions.
But there are other ways to get a value into a _Bool than via a
conversion.
That's true but it doesn't change the result. The question
is what values can _Bool hold as documented values (ie, and
not trap representations), and these are constrained by
conversion rules to be only 0 and 1 (if the implementation
is conforming). Clearly if a _Bool contains a trap
representation then all bets are off, just like any other
undefined behavior. But if what is held isn't a trap
representation then the value must be either 0 or 1.
Keith Thompson said:Tim Rentsch said:Ben Bacarisse said:Use int as a replacement type for _Bool, since any expression
where you use _Bool that expects an integer type will promote
_Bool to int, anyhow.
_Bool is an unsigned type.
right, but you will not notice this much.
I don't with a real _Bool, I do with a standin bool.
In any kind of arithmetic or comparison it will always be
promoted to an int since the two legal values of _Bool
always fit into and int.
To nitpick, C99 does not say that 0 and 1 are the only legal
values for bool, [snip elaboration]
Not said explicitly, but this does hold as a logical consequence
of the rules governing conversions.
But there are other ways to get a value into a _Bool than via a
conversion.
That's true but it doesn't change the result. The question
is what values can _Bool hold as documented values (ie, and
not trap representations), and these are constrained by
conversion rules to be only 0 and 1 (if the implementation
is conforming). Clearly if a _Bool contains a trap
representation then all bets are off, just like any other
undefined behavior. But if what is held isn't a trap
representation then the value must be either 0 or 1.
If, for a given implementation, all representations of _Bool other
than 0 and 1 are trap representations, then what you say is correct
for that implementation. I'm not sure whether it's correct for
all implementations.
Assume CHAR_BIT==8, sizeof(_Bool)==1, and _Bool has no trap
representations.
#include <stdio.h>
int main(void) {
union {
unsigned char c;
_Bool b;
} u;
u.c = 2;
printf("sizeof(_Bool) = %d, sizeof u = %d, u.b = %d\n",
(int)sizeof(_Bool),
(int)sizeof u,
(int)u.b);
return 0;
}
On my system, this program prints:
sizeof(_Bool) = 1, sizeof u = 1, u.b = 2
See the footnote in C99 6.5.2.3 (it's footnote #82 in N1256):
If the member used to access the contents of a union object
is not the same as the member last used to store a value in
the object, the appropriate part of the object representation
of the value is reinterpreted as an object representation in
the new type as described in 6.2.6 (a process sometimes called
"type punning"). This might be a trap representation.
I don't believe this program violates any constraint or exhibits
undefined behavior.
Interestingly, with optimization enabled, it shows "u.b = 0";
I wonder if that's a violation of the standard.
I suspect the standard is insufficiently clear about the behavior of
_Bool in some circumstances.
Kiki Thompson said:If, for a given implementation, all representations of _Bool other
than 0 and 1 are trap representations, then what you say is correct
for that implementation. I'm not sure whether it's correct for
all implementations.
etc, etc...
Malcolm said:Bool breaks libraries. Just return an int, to be on the safe side.
Tim Rentsch said:Ben Bacarisse said:Tim Rentsch said:_Bool is an unsigned type. ....
In any kind of arithmetic or comparison it will always be
promoted to an int since the two legal values of _Bool
always fit into and int.
To nitpick, C99 does not say that 0 and 1 are the only legal
values for bool, [snip elaboration]
Not said explicitly, but this does hold as a logical
consequence of the rules governing conversions.
But there are other ways to get a value into a _Bool than via a
conversion.
That's true but it doesn't change the result. The question is
what values can _Bool hold as documented values (ie, and not trap
representations),
and these are constrained by conversion rules to be only 0 and 1
(if the implementation is conforming).
Clearly if a _Bool contains a trap representation then all bets
are off, just like any other undefined behavior.
But if what is held isn't a trap representation then the value
must be either 0 or 1.
Yes, don't even include stdbool.h.Do you mean not even use this header or don't use true just 1 andnot
false just 0?
Peter Nilsson said:Tim Rentsch said:Ben Bacarisse said:_Bool is an unsigned type. ...
In any kind of arithmetic or comparison it will always be
promoted to an int since the two legal values of _Bool
always fit into and int.
To nitpick, C99 does not say that 0 and 1 are the only legal
values for bool, [snip elaboration]
Not said explicitly, but this does hold as a logical
consequence of the rules governing conversions.
But there are other ways to get a value into a _Bool than via a
conversion.
That's true but it doesn't change the result. The question is
what values can _Bool hold as documented values (ie, and not trap
representations),
My last assertion was that _Bool's integer promotion can potentially
be to unsigned int.
"An object declared as type _Bool is large enough to store the
values 0 and 1."[1] There is nothing stating that _Bool must only
have 1 value bit, just as UINT_MAX being at least 65535 is not a
statement that it can only be 65535.
and these are constrained by conversion rules to be only 0 and 1
That mearely constrains the values that result from conversion.
You haven't demonstrated it would be non-conforming.
True, but not the issue.
If it isn't a trap representation then all you can say is the value
is appropriate to the object type.
The Committee's Response in DR335 says _Bool has an implementation
defined width. Has there been any advance on that?
Malcolm McLean said:Yes, don't even include stdbool.h.
If you want to return a boolean, return an int, if you want to pass
one, pass as an int. If you need to pass or return several booleans,
pack them into an int.
Compare explictly to zero or non-zero.
It's not ideal, but it's the best you can do with the language as it
is. The alternative is that you get bools and Bools and bool_ts, and
that becomes confusing.
Keith Thompson said:(Note that such libraries are already incompatible with C++, in
which bool, false, and true are keywords.)
Ben Bacarisse said:Peter Nilsson said:Tim Rentsch said:But there are other ways to get a value into a _Bool than
via a conversion.
That's true but it doesn't change the result. The question
is what values can _Bool hold as documented values (ie, and
not trap representations),
My last assertion was that _Bool's integer promotion can
potentially be to unsigned int.
"An object declared as type _Bool is large enough to store the
values 0 and 1."[1] There is nothing stating that _Bool must
only have 1 value bit, just as UINT_MAX being at least 65535 is
not a statement that it can only be 65535.
and these are constrained by conversion rules to be only 0
and 1
That mearely constrains the values that result from conversion.
But, crucially, this combines with 6.3 p2 ("conversion of an
operand value to a compatible type causes no change to the value
...") to mean that only 0 and 1 are possible values. _Bool is
compatible with _Bool, so for any _Bool b, (_Bool)b must be 0 or
1 and must not change the value of b. ...
The width includes any padding bits.
If the response suggests that _Bool can have >1 value bits
(sorry, I haven't read it) ...
Peter Nilsson said:Ben Bacarisse said:Peter Nilsson said:But there are other ways to get a value into a _Bool than
via a conversion.
That's true but it doesn't change the result. The question
is what values can _Bool hold as documented values (ie, and
not trap representations),
My last assertion was that _Bool's integer promotion can
potentially be to unsigned int.
"An object declared as type _Bool is large enough to store the
values 0 and 1."[1] There is nothing stating that _Bool must
only have 1 value bit, just as UINT_MAX being at least 65535 is
not a statement that it can only be 65535.
and these are constrained by conversion rules to be only 0
and 1
That mearely constrains the values that result from conversion.
But, crucially, this combines with 6.3 p2 ("conversion of an
operand value to a compatible type causes no change to the value
...") to mean that only 0 and 1 are possible values. _Bool is
compatible with _Bool, so for any _Bool b, (_Bool)b must be 0 or
1 and must not change the value of b. ...
No conversion is required to convert a _Bool to a _Bool. Under
[n1256] 6.5.4p4 "A cast that specifies no conversion has no effect
on the type or value of an expression."
"The precision of an integer type is the number of bits it uses
to represent values, excluding any sign and padding bits. The
width of an integer type is the same but including any sign
bit; ..."
Tim Rentsch said:Keith Thompson said:Use int as a replacement type for _Bool, since any expression
where you use _Bool that expects an integer type will promote
_Bool to int, anyhow.
_Bool is an unsigned type.
right, but you will not notice this much.
I don't with a real _Bool, I do with a standin bool.
In any kind of arithmetic or comparison it will always be
promoted to an int since the two legal values of _Bool
always fit into and int.
To nitpick, C99 does not say that 0 and 1 are the only legal
values for bool, [snip elaboration]
Not said explicitly, but this does hold as a logical consequence
of the rules governing conversions.
But there are other ways to get a value into a _Bool than via a
conversion.
That's true but it doesn't change the result. The question
is what values can _Bool hold as documented values (ie, and
not trap representations), and these are constrained by
conversion rules to be only 0 and 1 (if the implementation
is conforming). Clearly if a _Bool contains a trap
representation then all bets are off, just like any other
undefined behavior. But if what is held isn't a trap
representation then the value must be either 0 or 1.
If, for a given implementation, all representations of _Bool other
than 0 and 1 are trap representations, then what you say is correct
for that implementation. I'm not sure whether it's correct for
all implementations.
Assume CHAR_BIT==8, sizeof(_Bool)==1, and _Bool has no trap
representations.Then one of two things must be true, either: one, _Bool
has 7 padding bits; or two, _Bool has more than 1 value
bit.If _Bool has 7 padding bits, then the program you
give (below) won't print 'u.b = 2' in a conforming
implementation.
Agreed, because the padding bits by definition don't contribute to
the value.
If _Bool has more than 1 value bit, then an implementation
cannot simultaneously satisfy 6.3p2 and 6.3.1.2p1. Hence
such an implementation cannot be conforming.The conclusion is that either this implementation is
not conforming, or that its _Bool does indeed have
trap representations.
As has happened several times before, I was in the middle of composing a
refutation of these last two points when I realized you're right.
When I convert the value of u.b to _Bool (a conversion from _Bool to
_Bool), the result is 1 -- which violates 6.3p2 unless u.b held a trap
representation.
I couldn't find any discussion of _Bool's trap
representations and/or padding bits, or lack thereof,
in the gcc documentation, but I did find something in
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1356.htm>:
Joseph S. Myers' reading of this issue is:
The "width" of a type is the number of value and sign bits
(6.2.6.2#6), so post-TC2 a _Bool:CHAR_BIT bit-field is valid
only if the implementation defines _Bool to have CHAR_BIT value
bits. GCC defines it to have one value bit with the other bits
being padding bits and undefined behavior if you access a _Bool
representation with any of the padding bits having a nonzero
value (such representations being trap representations). Thus the
width of _Bool is 1 with GCC and the diagnostics are required.
So for gcc (assuming Joseph S. Myers is correct, and it certainly makes
sense), _Bool has 1 value bit and 7 padding bits, and all but 2 of its
256 possible representations are trap representations.
As far as I can tell, _Bool *cannot* have more than 1 value bit, and
must have exactly CHAR_BIT-1 padding bits. If, in addition, it has no
trap representations, then evaluating a _Bool object must ignore all but
the single value bit, yielding either 0 or 1. If it does have trap
representations (as gcc does), evaluating one of them has undefined
behavior and may yield (or do) anything.
[snip]
I believe it's a consequence of undefined behavior caused
by the presence of a converted trap representation.
Makes sense.
[snip]
--
Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"- Hide quoted text-
- Show quoted text -
Keith Thompson said:...
When I convert the value of u.b to _Bool (a conversion from
_Bool to _Bool)...
Peter Nilsson said:_Bool to _Bool does not require a conversion, a _Bool *is* a _Bool.
Peter Nilsson said:_Bool to _Bool does not require a conversion, a _Bool *is* a _Bool.
Peter Nilsson said:Ben Bacarisse said:Peter Nilsson said:But there are other ways to get a value into a _Bool than
via a conversion.
That's true but it doesn't change the result. The question
is what values can _Bool hold as documented values (ie, and
not trap representations),
My last assertion was that _Bool's integer promotion can
potentially be to unsigned int.
"An object declared as type _Bool is large enough to store the
values 0 and 1."[1] There is nothing stating that _Bool must
only have 1 value bit, just as UINT_MAX being at least 65535 is
not a statement that it can only be 65535.
and these are constrained by conversion rules to be only 0
and 1
That mearely constrains the values that result from conversion.
But, crucially, this combines with 6.3 p2 ("conversion of an
operand value to a compatible type causes no change to the value
...") to mean that only 0 and 1 are possible values. _Bool is
compatible with _Bool, so for any _Bool b, (_Bool)b must be 0 or
1 and must not change the value of b. ...
No conversion is required to convert a _Bool to a _Bool. Under
[n1256] 6.5.4p4 "A cast that specifies no conversion has no effect
on the type or value of an expression."
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.