svn commit: r295833 - head/sys/sys
Bruce Evans
brde at optusnet.com.au
Sat Feb 20 04:42:15 UTC 2016
On Sat, 20 Feb 2016, Justin Hibbits wrote:
> Log:
> Fix the definition of RM_MAX_END.
>
> Even though casting from signed to unsigned is well-defined in C, it's better to
> first cast to the larger unsigned type, then negate.
Casting ~0 is well-defined, but ~0 isn't.
The operation is complementation, not negation.
> Modified: head/sys/sys/rman.h
> ==============================================================================
> --- head/sys/sys/rman.h Sat Feb 20 01:32:58 2016 (r295832)
> +++ head/sys/sys/rman.h Sat Feb 20 01:34:13 2016 (r295833)
> @@ -61,7 +61,7 @@ enum rman_type { RMAN_UNINIT = 0, RMAN_G
> */
> #define RM_TEXTLEN 32
>
> -#define RM_MAX_END ((rman_res_t)~0)
> +#define RM_MAX_END (~(rman_res_t)0)
If the operation were negation, then its result -0 would actually be well-
defined. It would be 0 again, even in the 1's complement and signed
magnitude cases where -0 can be represented. -0 cast to unsigned must
give 0 again, and not be all-bits-1 even if it started as all-bits 1
representing -0 in 2's complement.
~0 was under-specified in C90 as being the bitwise complement. The value
of that is not specified unless the promotion of the orginal type is
unsigned (~(unsigned char)0 is also not specified except on exotic
machines (no longer permitted by POSIX) with unsigned char the same size
as unsigned int).
~0 is even more under-specified in C99 because C99 is more careful
with representations and has trap representations. (This is not fixed
in C11.) Complementing a non- trap-representation might give a trap
representation if done bitwise, even starting from a nondescript value
like 0. But if there are no trap or padding bits, the only reasonable
interpretation of the spec is that ~0 gives all-bits-1 with whatever
value that has. In the 2's complement case, the value is -1 and casting
this to unsigned works right. In the 1's complement case, the value
is -0 and casting this to unsigned gives unsigned plain 0. In the
signed-magnitude case, I think it gives -0x7fffffff with 32-bit ints
and casting this to unsigned gives 0x80000001. C90 allows other
representations, so the result can be anything.
The clearest way to write the expression is probably ((rman_res_t)-1)
like the buggy ~0 version did in the 2's complement case.
Everyone knows what -1 is. Conversion of -1 to unsigned is better
known than what ~0 is. It takes an explicit specification for both.
Conversion of -1 involves "[in extra precision] repeatedly adding or
subtracting one more than the maximim value that can be represented
in the new type until [the result is representable]". Thus
((rman_res_t)-1) is maxof(rman_res_t) + 1 - 1 == maxof(rman_res_t).
(~(rman_res_t)0) involves the specification of the '~' operator
saying that complementing the bits actually works for the unsigned
case. The precise wording is "If the promoted type [of E] is an
unsigned type, then the expression ~E is equivalent to the maximum
value representable in that type minus E". Thus (~(rman_res_t)0)
is maxof(rman_res_t) - 0 = maxof(rman_res_t). I think the precise
wording is redundant, but this is not clear. Something is needed
to ensure that complementing bits doesn't give a trap representation
for the unsigned case. Complementing only value bits wouldn't give
a trap representation, but complementing padding bits could (should)
give a trap representation. The spec is too fuzzy to say which bits
are complemented, except in the unsigned case padding bits must not
be complemented if this would give a trap representation.
Bruce
More information about the svn-src-all
mailing list