Velocity Reviews > Weary of using -1 for max unsigned values

# Weary of using -1 for max unsigned values

Martin Wells
Guest
Posts: n/a

 10-25-2007

I commonly use the likes of -1 for max unsigned values, or something
like -7 to get 6 away from the max value; sort of like:

unsigned x = ...

if (-7 == x) puts("x is 6 away from its maximum");

Since I rarely use anything smaller than int, this has never been a
problem. Obviously though, there'd be a problem if I tried:

char unsigned x = ...

if (-7 == x) puts("x is 6 away...

The reason there'd be a problem is that x could be promoted to a
SIGNED int.

So I'm wondering... what's the handiest way of checking this for any
unsigned integer expression?

In the case of unsigned char, we can do
if ((char unsigned)-7 == x)

Similarly in the case of unsigned short, we can do
if ((short unsigned)-7) == x)

But what I'm looking for is a universal method. My first thoughts were
something like

#define MAX(expr) ( (expr) * (char_unsigned)0 - (char
unsigned)1 )

The problem with this of course though is that, even though we have
the casts, everything will still get promoted to int (either signed or
unsigned depending on INT_MAX).

Anyone got any ideas such that I can write universal code such as?:

if (MAX(x)-6 == x) puts("x is 6 away from its maximum");

If we had a typeof operator it would probably be something like:

#define MAX(expr) ( (typeof expr)-1 )

I have the likes of "-1 == x" littered throughout my code... and yes
it works fine... but I'd like something more sustainable just in case
I'd choose to use something smaller than an int.

Martin

jameskuyper@verizon.net
Guest
Posts: n/a

 10-25-2007
Martin Wells wrote:
> I commonly use the likes of -1 for max unsigned values, or something
> like -7 to get 6 away from the max value; sort of like:
>
> unsigned x = ...
>
> if (-7 == x) puts("x is 6 away from its maximum");
>
> Since I rarely use anything smaller than int, this has never been a
> problem. Obviously though, there'd be a problem if I tried:
>
> char unsigned x = ...
>
> if (-7 == x) puts("x is 6 away...
>
> The reason there'd be a problem is that x could be promoted to a
> SIGNED int.
>
> So I'm wondering... what's the handiest way of checking this for any
> unsigned integer expression?

if (UINT_MAX-6 == x ) ...

Replace UINT_MAX with UCHAR_MAX, USHRT_MAX, ULONG_MAX, ULLONG_MAX, or
SIZE_MAX, as appropriate.

Martin Wells
Guest
Posts: n/a

 10-25-2007
james:

> if (UINT_MAX-6 == x ) ...
>
> Replace UINT_MAX with UCHAR_MAX, USHRT_MAX, ULONG_MAX, ULLONG_MAX, or
> SIZE_MAX, as appropriate

Using TYPE_MAX is no more universal than (TYPE)-1. I'm looking for
something I can use with any unsigned integer type.

Martin

vipvipvipvipvip.ru@gmail.com
Guest
Posts: n/a

 10-25-2007
Martin Wells you come up with the silliest problems.
first memset, now this..

Ian Collins
Guest
Posts: n/a

 10-25-2007
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> Martin Wells you come up with the silliest problems.
> first memset, now this..
>

Now what? Please retain enough context for your post to make sense.

--
Ian Collins.

Mark McIntyre
Guest
Posts: n/a

 10-25-2007
On Thu, 25 Oct 2007 13:16:41 -0700, in comp.lang.c , Martin Wells
<(E-Mail Removed)> wrote:

>james:
>
>> if (UINT_MAX-6 == x ) ...
>>
>> Replace UINT_MAX with UCHAR_MAX, USHRT_MAX, ULONG_MAX, ULLONG_MAX, or
>> SIZE_MAX, as appropriate

>
>
>Using TYPE_MAX is no more universal than (TYPE)-1. I'm looking for
>something I can use with any unsigned integer type.

Seems to me you want a template type.
Unfortunately C++ is thattaway ---->>

BTW I can't say I've ever encountered any actual real-world example of
your problem, so perhaps this is a solution looking for a problem...
..
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan

Charlie Gordon
Guest
Posts: n/a

 10-26-2007
"Martin Wells" <(E-Mail Removed)> a écrit dans le message de news:
(E-Mail Removed) om...
> james:
>
>> if (UINT_MAX-6 == x ) ...
>>
>> Replace UINT_MAX with UCHAR_MAX, USHRT_MAX, ULONG_MAX, ULLONG_MAX, or
>> SIZE_MAX, as appropriate

>
>
> Using TYPE_MAX is no more universal than (TYPE)-1. I'm looking for
> something I can use with any unsigned integer type.

Here is one:

#define MWELLS_CMP(val, x) \
(((unsigned long long)(long long)(val) & \
(-1ULL >> ((sizeof(1ULL) - sizeof(x)) * CHAR_BIT)) == (x))

Use it as:

if (MWELLS_CMP(-6, x)) ...

It should work for any x with unsigned type.
Both val and x are evaluated once in the macro expansion.
A smart compiler should generate efficient code for types smaller than
unsigned long long, but it might not.

--
Chqrlie.

Martin Wells
Guest
Posts: n/a

 10-26-2007
Chqrlie:

> #define MWELLS_CMP(val, x) \
> (((unsigned long long)(long long)(val) & \
> (-1ULL >> ((sizeof(1ULL) - sizeof(x)) * CHAR_BIT)) == (x))
>
> Use it as:
>
> if (MWELLS_CMP(-6, x)) ...

(You've got an extra open parenthesis at the very start)

I'm gonna think out loud here and see if I understand it

(

(unsigned long long)(long long)(val)

Here you take val, convert it to a long long, then to an unsigned long
long. Why don't you go straight to an unsigned long long?

&
(
-1ULL >>
( (sizeof(1ULL) - sizeof(x)) * CHAR_BIT )
)

== (x)
)

Now you take the byte difference between unsigned long long and the
expression, and multiply it by CHAR_BIT to get the bit difference. You
shift the max value of unsigned long long to the right by this bit
difference. You then compare this value to X, yielding an int value of
either 1 or 0, and you then bitwiseAND this with the previous value
above. I haven't fully thought it through but it seems you might have
an error above as regards operands and operator precedence. Anyway,
two flaws that stick out are:

1) Unsigned types can have padding, so sizeof isn't reliable for the
amount of value representational bits.
2) Use of unsigned long long is specific to C99. If we're gonna bother
with C99, then we'd be better off to go with int_max_t or whatever
it's called. As for C89, we can only go with unsigned long... but the
implemenation could provide a bigger type.

Martin

Dan Henry
Guest
Posts: n/a

 10-27-2007
On Thu, 25 Oct 2007 10:48:01 -0700, Martin Wells <(E-Mail Removed)>
wrote:

>
>I commonly use the likes of -1 for max unsigned values, ...

-1 does not convert to the maximum unsigned value for one's complement
representation.

--
Dan Henry

James Kuyper
Guest
Posts: n/a

 10-27-2007
Dan Henry wrote:
> On Thu, 25 Oct 2007 10:48:01 -0700, Martin Wells <(E-Mail Removed)>
> wrote:
>
>> I commonly use the likes of -1 for max unsigned values, ...

>
> -1 does not convert to the maximum unsigned value for one's complement
> representation.

The representation of the signed integer type is irrelevant. It's the
value that gets converted, not it's representation. The relevant rule is
given in 6.3.1.3p2:

"Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or subtracting one more than the maximum value that
can be represented in the new type until the value is in the range of
the new type."

In the case of -1, that means adding "one more than the maximum value"
to -1, which gives you exactly the maximum value.