Weary of using -1 for max unsigned values

Discussion in 'C Programming' started by Martin Wells, Oct 25, 2007.

  1. Martin Wells

    Martin Wells Guest

    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
     
    Martin Wells, Oct 25, 2007
    #1
    1. Advertising

  2. Martin Wells

    Guest

    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.
     
    , Oct 25, 2007
    #2
    1. Advertising

  3. Martin Wells

    Martin Wells Guest

    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
     
    Martin Wells, Oct 25, 2007
    #3
  4. Martin Wells

    Guest

    Martin Wells you come up with the silliest problems.
    first memset, now this..
     
    , Oct 25, 2007
    #4
  5. Martin Wells

    Ian Collins Guest

    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.
     
    Ian Collins, Oct 25, 2007
    #5
  6. On Thu, 25 Oct 2007 13:16:41 -0700, in comp.lang.c , Martin Wells
    <> 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
     
    Mark McIntyre, Oct 25, 2007
    #6
  7. "Martin Wells" <> a écrit dans le message de news:
    ...
    > 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.
     
    Charlie Gordon, Oct 26, 2007
    #7
  8. Martin Wells

    Martin Wells Guest

    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
     
    Martin Wells, Oct 26, 2007
    #8
  9. Martin Wells

    Dan Henry Guest

    On Thu, 25 Oct 2007 10:48:01 -0700, Martin Wells <>
    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
     
    Dan Henry, Oct 27, 2007
    #9
  10. Martin Wells

    James Kuyper Guest

    Dan Henry wrote:
    > On Thu, 25 Oct 2007 10:48:01 -0700, Martin Wells <>
    > 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.
     
    James Kuyper, Oct 27, 2007
    #10
  11. Martin Wells

    CBFalconer Guest

    Dan Henry wrote:
    > Martin Wells <> 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.


    Yes it does. This is a portable technique.

    --
    Chuck F (cbfalconer at maineline dot net)
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net>



    --
    Posted via a free Usenet account from http://www.teranews.com
     
    CBFalconer, Oct 27, 2007
    #11
  12. "James Kuyper" <> a écrit dans le message de news:
    wsJUi.447$TO4.392@trnddc07...
    > Dan Henry wrote:
    >> On Thu, 25 Oct 2007 10:48:01 -0700, Martin Wells <>
    >> 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.


    The likely consequence of this is that casting a int to unsigned on one of
    those obsolete museum pieces emits code, possibly even a test and one or two
    jumps.

    One's complement is nothing to worry about.

    --
    Chqrlie.
     
    Charlie Gordon, Oct 27, 2007
    #12
  13. "Martin Wells" <> a écrit dans le message de news:
    ...
    > 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)


    Actually, there is a missing parenthesis after CHAR_BIT.

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

    > 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?


    no good reason, let's simplify:

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

    > &
    > (
    > -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.


    Correct: this produces the value UCHAR_MAX, UINT_MAX, ULONG_MAX or
    ULLONG_MAX depending on the type of x.

    > 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.


    With the missing parenthesis, the value produced in the step above is used
    to mask off the high bits of val sign extended to (at least) 64 bits.

    > 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.


    Good point: the C standard "supports" braindead (padding) and obsolete (non
    2's complement) architectures, but the commitee forgot simple macros telling
    the gory details, it is non trivial to derive INT_BIT from INT_MAX in a
    macro, but can be done.

    > 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.


    obviously, you can tailor the macro for strict c89 and c99:

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

    #define MWELLS_CMP99(val, x) \
    (((uintmax_t)(val) & \
    ((uintmax_t)-1 >> ((sizeof(uintmax_t) - sizeof(x)) * CHAR_BIT))) ==
    (x))

    Enjoy!

    --
    Chqrlie.
     
    Charlie Gordon, Oct 27, 2007
    #13
  14. Martin Wells

    Dan Henry Guest

    On Sat, 27 Oct 2007 16:13:16 GMT, James Kuyper
    <> wrote:

    >Dan Henry wrote:
    >> On Thu, 25 Oct 2007 10:48:01 -0700, Martin Wells <>
    >> 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.


    I was in a bit pattern frame of mind, but am feeling better now.

    --
    Dan Henry
     
    Dan Henry, Oct 28, 2007
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Summercool
    Replies:
    9
    Views:
    927
    dorayme
    Oct 23, 2007
  2. Replies:
    3
    Views:
    462
    James Kanze
    Nov 19, 2008
  3. pozz
    Replies:
    12
    Views:
    795
    Tim Rentsch
    Mar 20, 2011
  4. Greg Ferris

    Textarea max rows and max characters per row

    Greg Ferris, Jan 16, 2004, in forum: Javascript
    Replies:
    2
    Views:
    630
    Greg Ferris
    Jan 16, 2004
  5. kriton
    Replies:
    0
    Views:
    369
    kriton
    Apr 22, 2005
Loading...

Share This Page