Portable assignment

M

Martin

I am reviewing this function:

unsigned long function(unsigned long *first, unsigned long *last)
{
unsigned long diff;

if ( (*last) < (*first) /* rollover occured */
{
period = (0xFFFFFFFF - (*first)) + (*last) + 1;
}
else /* no rollover */
{
period = (*last) - (*first);
}

return period;
}


The statement
period = (0xFFFFFFFF - (*first)) + (*last) + 1;
assumes a long is 32 bits wide. I noticed in K&R2 they talked about a
portable way of defining a constant - without assuming a particular width. I
came up with these:

Suggestion 1:
period = (~0UL - (*first)) + (*last) + 1;

Suggestion 2:
period = (ULONG_MAX - (*first)) + (*last) + 1;

The point of Suggestion 1 is that it sets all bits in an unsigned long,
irrespective of the width it happens to be. Suggestion 2 uses the symbolic
constant ULONG_MAX (the maximum value for an object of type unsigned long
int).

My questions are these:
(i) Am I right to try and make this non-width specific?
(ii) Do my suggestions so do?

Finally, as an adjunct, if I wanted to set a value, say 0xFFD1 in an
unsigned int that happens to be 16 bits wide at the moment, would I be
better off doing something like this:

ui = ~0x2EU;

so later when it's 24 or 32 bits, or whatever, all bits except 1, 2, 3, and
5 are still set?
 
L

lawrence.jones

Martin said:
My questions are these:
(i) Am I right to try and make this non-width specific?
Yes.

(ii) Do my suggestions so do?

Yes. However, you've overlooked a much better solution to the problem. Due
to the properties of unsigned arithmetic in C:
period = (0xFFFFFFFF - (*first)) + (*last) + 1;

computes exactly the same value (assuming 32-bit longs) as:
period = (*last) - (*first);

So there's no need for any constant. In fact, there's no need for the
function itself since the simple, obvious expression works correctly,
even in the case of (a single) wrap around!

-Larry Jones

You should see me when I lose in real life! -- Calvin
 
C

Chris Torek

Larry Jones already answered the main question (and noted one
of the very useful properties of unsigned arithmetic: ordinary
subtraction always gives the desired result).

Finally, as an adjunct, if I wanted to set a value, say 0xFFD1 in an
unsigned int that happens to be 16 bits wide at the moment, would I be
better off doing something like this:

ui = ~0x2EU;

so later when it's 24 or 32 bits, or whatever, all bits except 1, 2, 3, and
5 are still set?

It is certainly a good idea to consider this option. The question
then becomes whether you want to set any "new" (higher-order) bits
that appear in the unsigned type when it has a bigger U<type>_MAX
value. This depends on the "intended purpose" of the unsigned int,
rather than its actual representation in a 16-or-more-bit unit.
 
C

Christian Bau

"Martin said:
I am reviewing this function:

unsigned long function(unsigned long *first, unsigned long *last)
{
unsigned long diff;

if ( (*last) < (*first) /* rollover occured */
{
period = (0xFFFFFFFF - (*first)) + (*last) + 1;
}
else /* no rollover */
{
period = (*last) - (*first);
}

return period;
}

Very strange. If unsigned long is 32 bit, then this will always return
the same value as

return *last - *first;

If unsigned long is more than 32 bit, then the result is very likely not
what the programmer intended. You could just change this to

unsigned long function (unsigned long *first, unsigned long *last)
{
return *last - *first;
}
 

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
474,139
Messages
2,570,807
Members
47,356
Latest member
Tommyhotly

Latest Threads

Top