[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Dealing with wrap-around in unsigned differences

Barry Briggs

8/24/2011 12:36:00 PM

Hello,

I've come across the following macro:

/** Get the absolute difference between 2 u32_t values (correcting overflows)
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
#define FOO_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))

(u32_t is equivalent to uint32_t)

In my opinion, the entire macro reduces to ((a)-(b)) since
((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
arithmetic is carried out modulo 2^32).

Do you agree that the macro can be simplified, with no loss
in portability whatsoever?

I wrote a small program to try to illustrate my point.

#include <stdio.h>
int main(void)
{
volatile unsigned b = 0;
do
{
unsigned v1 = (b ^ 0xFFFFFFFF) + 1;
unsigned v2 = -b;
if (v1 != v2) printf("b=%u v1=%u v2=%u\n", b, v1, v2);
}
while (++b != 0);
return 0;
}

My compiler generates the same instruction to compute
v1 and v2.

Regards.
5 Answers

Richard Damon

8/24/2011 4:19:00 PM

0

On 8/24/11 8:35 AM, Noob wrote:
> Hello,
>
> I've come across the following macro:
>
> /** Get the absolute difference between 2 u32_t values (correcting overflows)
> * 'a' is expected to be 'higher' (without overflow) than 'b'. */
> #define FOO_U32_DIFF(a, b) (((a)>= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
>
> (u32_t is equivalent to uint32_t)
>
> In my opinion, the entire macro reduces to ((a)-(b)) since
> ((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
> arithmetic is carried out modulo 2^32).
>
> Do you agree that the macro can be simplified, with no loss
> in portability whatsoever?
>

My guess is that this is code to emulate uint32_t on a machine that
doesn't have a proper uint32_t, or may not be of type uint32_t. (perhaps
u32 is an 36 or 64 bit unsigned, as that is as close as the platform
provides, but they needed exact emulation for this result.

Peter Nilsson

8/24/2011 10:50:00 PM

0

Noob <r...@127.0.0.1> wrote:
> I've come across the following macro:
>
> /** Get the absolute difference between 2 u32_t values
> (correcting overflows) * 'a' is expected to be 'higher'
> (without overflow) than 'b'. */

Expected, but not required apparently! Is it really meant
to get the _absolute_ difference?

> #define FOO_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b))
> : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
>
> (u32_t is equivalent to uint32_t)
>
> In my opinion, the entire macro reduces to ((a)-(b)) since
> ((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
> arithmetic is carried out modulo 2^32).

You're assuming uint32_t doesn't promote to int. The macro
can be written as...

#define FOO_U32_DIFF(a, b) ( (u32_t) ((a) - (b)) )

Assuming u32_t is an unsigned type.

> Do you agree that the macro can be simplified, with no loss
> in portability whatsoever?

It all hinges on what exactly u32_t is, or rather could be.
I'm guessing it's set up with some conditional preprocessing.

Perhaps it's really more like uint_least32_t, in which case
the macro may not work when b == 0 anyway. If it is meant to
mimic uint32_t, but may be wider, then the following may be
better:

#define FOO_U32_DIFF(a, b) \
( (u32_t) ((0ul + (a) - (b)) & 0xFFFFFFFFul) )

--
Peter

Jorgen Grahn

8/27/2011 6:14:00 PM

0

On Wed, 2011-08-24, Richard Damon wrote:
....
> My guess is that this is code to emulate uint32_t on a machine that
> doesn't have a proper uint32_t, or may not be of type uint32_t. (perhaps
> u32 is an 36 or 64 bit unsigned, as that is as close as the platform
> provides, but they needed exact emulation for this result.

What do you mean by "may not be of type uint32_t"?

Surely, uint32_t has to be exactly 32 bits if your environment
provides it? There's uint_least32_t for the other cases.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Jorgen Grahn

8/27/2011 6:16:00 PM

0

On Wed, 2011-08-24, Noob wrote:
> Hello,
>
> I've come across the following macro:
>
> /** Get the absolute difference between 2 u32_t values (correcting overflows)
> * 'a' is expected to be 'higher' (without overflow) than 'b'. */
> #define FOO_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
>
> (u32_t is equivalent to uint32_t)
>
> In my opinion, the entire macro reduces to ((a)-(b)) since
> ((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
> arithmetic is carried out modulo 2^32).
>
> Do you agree that the macro can be simplified, with no loss
> in portability whatsoever?

I don't know, but I'd definitely make it an (inline) function, to avoid
driving people crazy. This isn't the 1980s.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Richard Damon

8/28/2011 1:41:00 AM

0

On 8/27/11 2:14 PM, Jorgen Grahn wrote:
> On Wed, 2011-08-24, Richard Damon wrote:
> ...
>> My guess is that this is code to emulate uint32_t on a machine that
>> doesn't have a proper uint32_t, or may not be of type uint32_t. (perhaps
>> u32 is an 36 or 64 bit unsigned, as that is as close as the platform
>> provides, but they needed exact emulation for this result.
>
> What do you mean by "may not be of type uint32_t"?
>
> Surely, uint32_t has to be exactly 32 bits if your environment
> provides it? There's uint_least32_t for the other cases.
>
> /Jorgen
>

The code calls the type U32, not uint32_t. It also is a macro so we
don't really know what type the parameters are.

If the type IS uint32_t, the extra complication should not be needed, so
my assumption is that the programmer didn't want to assume that this is
what he had, but did want the results as if he had them.