Portable way to mask the LSB

Discussion in 'C Programming' started by Francis Moreau, May 29, 2010.

  1. Hello,

    I just realize that I'm not sure how to do this in a portable way.

    Consider this piece of code:

    unsigned long u;
    /* ... */
    u = u & ~1; /* mask the LSB */

    In my understanding, this only works if the value of the expression
    '~1' is -2. So it depends on how object with signed integer type are
    encoded (2's complement, 1's complement ...).

    Is this correct ?

    If so, how should I rewrite the code to make it portable ?

    u = u & ~1UL;
    u = u & ~(unsigned long)1;
    or
    u = u & (ULONG_MAX - 1);

    Are these alternatives correct ?

    Thanks
    Francis Moreau, May 29, 2010
    #1
    1. Advertising

  2. Francis Moreau

    Moi Guest

    On Sat, 29 May 2010 05:32:12 -0700, Francis Moreau wrote:

    > Hello,
    >
    > I just realize that I'm not sure how to do this in a portable way.
    >
    > Consider this piece of code:
    >
    > unsigned long u;
    > /* ... */
    > u = u & ~1; /* mask the LSB */
    >
    > In my understanding, this only works if the value of the expression '~1'
    > is -2. So it depends on how object with signed integer type are encoded
    > (2's complement, 1's complement ...).
    >
    > Is this correct ?
    >
    > If so, how should I rewrite the code to make it portable ?
    >
    > u = u & ~1UL;


    This one seems reasonable to me.

    > u = u & ~(unsigned long)1;
    > or
    > u = u & (ULONG_MAX - 1);
    >
    > Are these alternatives correct ?
    >
    > Thanks


    Don't forget
    u = ((u >>1) <<1);

    HTH,
    AvK
    Moi, May 29, 2010
    #2
    1. Advertising

  3. Francis Moreau

    Eric Sosman Guest

    On 5/29/2010 8:32 AM, Francis Moreau wrote:
    > Hello,
    >
    > I just realize that I'm not sure how to do this in a portable way.
    >
    > Consider this piece of code:
    >
    > unsigned long u;
    > /* ... */
    > u = u& ~1; /* mask the LSB */
    >
    > In my understanding, this only works if the value of the expression
    > '~1' is -2. So it depends on how object with signed integer type are
    > encoded (2's complement, 1's complement ...).
    >
    > Is this correct ?


    Yes. `~1' yields the bitwise complement of `1', consisting
    of a low-order zero bit and all the other bits set (including the
    sign bit). The numeric value of this batch of bits depends on how
    the system encodes negative integers: You could get -2 (two's
    complement), -1 (ones' complement), or 1-INT_MAX (signed magnitude).

    To apply the `&', `~1' is first converted to unsigned long,
    and this conversion is defined in terms of the numeric values of
    `~1' and of `ULONG_MAX'. Since there are three possible values
    for `~1', there are three possible outcomes for the conversion
    (only one outcome on any one machine, of course).

    > If so, how should I rewrite the code to make it portable ?
    >
    > u = u& ~1UL;
    > u = u& ~(unsigned long)1;
    > or
    > u = u& (ULONG_MAX - 1);
    >
    > Are these alternatives correct ?


    Yes. I would vote for `u &= ~1UL'. More generally, to clear
    the k'th bit, `u &= ~(1UL << k)'.

    --
    Eric Sosman
    lid
    Eric Sosman, May 29, 2010
    #3
  4. On 29 mai, 15:06, Moi <> wrote:
    > On Sat, 29 May 2010 05:32:12 -0700, Francis Moreau wrote:
    > > Hello,

    >
    > > I just realize that I'm not sure how to do this in a portable way.

    >
    > > Consider this piece of code:

    >
    > >     unsigned long u;
    > >     /* ... */
    > >     u = u & ~1; /* mask the LSB */

    >
    > > In my understanding, this only works if the value of the expression '~1'
    > > is -2. So it depends on how object with signed integer type are encoded
    > > (2's complement, 1's complement ...).

    >
    > > Is this correct ?

    >
    > > If so, how should I rewrite the code to make it portable ?

    >
    > >     u = u & ~1UL;

    >
    > This one seems reasonable to me.
    >
    > >     u = u & ~(unsigned long)1;
    > > or
    > >     u = u & (ULONG_MAX - 1);

    >
    > > Are these alternatives correct ?

    >
    > > Thanks

    >
    > Don't forget
    > u = ((u >>1) <<1);


    Do you think that this version could be faster ?

    Thanks
    Francis Moreau, May 30, 2010
    #4
  5. Francis Moreau

    Moi Guest

    On Sun, 30 May 2010 12:44:45 -0700, Francis Moreau wrote:

    > On 29 mai, 15:06, Moi <> wrote:
    >> On Sat, 29 May 2010 05:32:12 -0700, Francis Moreau wrote:
    >> > Hello,

    >>
    >> > I just realize that I'm not sure how to do this in a portable way.

    >>
    >> > Consider this piece of code:

    >>
    >> >     unsigned long u;
    >> >     /* ... */
    >> >     u = u & ~1; /* mask the LSB */

    >>
    >> > In my understanding, this only works if the value of the expression
    >> > '~1' is -2. So it depends on how object with signed integer type are
    >> > encoded (2's complement, 1's complement ...).

    >>
    >> > Is this correct ?

    >>
    >> > If so, how should I rewrite the code to make it portable ?

    >>
    >> >     u = u & ~1UL;

    >>
    >> This one seems reasonable to me.
    >>
    >> >     u = u & ~(unsigned long)1;
    >> > or
    >> >     u = u & (ULONG_MAX - 1);

    >>
    >> > Are these alternatives correct ?

    >>
    >> > Thanks

    >>
    >> Don't forget
    >> u = ((u >>1) <<1);

    >
    > Do you think that this version could be faster ?


    No.
    Basically, I don't care about speed.
    In trivial operations like this, it is the speed of access to the
    memory (or caches) that dominates the overall speed.
    In all cases it winds down to fetch+"some operations"+ one store.

    My suggestion has the advantage that there is no possible size mismatch;
    other ways to perform the same operation may be sensitive to the size of the
    bitmask-constant (~1 vs ~1ul vs ~1ull).
    Also, the bitmask constant may be compiled into a literal constant
    in the instruction stream, which may cost a 32 bit or 64 bit constant to be
    emitted. (GCC on intel mostly uses immediate 0xfe which gets sign-extended)

    BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
    instruction sequence as the &= ~1 or &= -1ull - versions.

    HTH,
    AvK
    Moi, May 30, 2010
    #5
  6. Francis Moreau

    Tom St Denis Guest

    On May 30, 5:10 pm, Moi <> wrote:
    > BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
    > instruction sequence as the &= ~1 or &= -1ull - versions.


    There is no such thing as -O6 in GCC. It goes up to 3 only.

    I suggest you read the GCC manpage sometime.

    Tom
    Tom St Denis, May 31, 2010
    #6
  7. On 31 mai, 12:56, Tom St Denis <> wrote:
    > On May 30, 5:10 pm, Moi <> wrote:
    >
    > > BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
    > > instruction sequence as the &= ~1 or &= -1ull - versions.

    >
    > There is no such thing as -O6 in GCC.  It goes up to 3 only.
    >
    > I suggest you read the GCC manpage sometime.


    Next time I suggest you just stop sending such useless posts.
    Francis Moreau, May 31, 2010
    #7
  8. Tom St Denis <> writes:
    > On May 30, 5:10 pm, Moi <> wrote:
    >> BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
    >> instruction sequence as the &= ~1 or &= -1ull - versions.

    >
    > There is no such thing as -O6 in GCC. It goes up to 3 only.
    >
    > I suggest you read the GCC manpage sometime.


    <OT>
    gcc quietly accepts "-O6". It doesn't seem to be documented, but
    as far as I can tell it's equivalent to "-O3". In fact, -On for
    any n greater than 3 appears to be equivalent to "-O3".
    </OT>

    --
    Keith Thompson (The_Other_Keith) <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"
    Keith Thompson, May 31, 2010
    #8
    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. Pierre Rouleau
    Replies:
    0
    Views:
    398
    Pierre Rouleau
    Dec 10, 2003
  2. Replies:
    9
    Views:
    966
    Juha Nieminen
    Aug 22, 2007
  3. LSB aligned data

    , Apr 18, 2008, in forum: C++
    Replies:
    3
    Views:
    402
    James Kanze
    Apr 18, 2008
  4. Marcin Tyman

    Conversion mask in hex to bit mask

    Marcin Tyman, May 6, 2008, in forum: Ruby
    Replies:
    4
    Views:
    801
    Robert Klemme
    May 6, 2008
  5. 187
    Replies:
    2
    Views:
    551
    Bart Lateur
    Jul 29, 2004
Loading...

Share This Page