Portable way to mask the LSB

F

Francis Moreau

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
 
M

Moi

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
 
E

Eric Sosman

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)'.
 
M

Moi

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
 
T

Tom St Denis

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
 
F

Francis Moreau

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

Keith Thompson

Tom St Denis said:
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>
 

Ask a Question

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.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top