avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-libc-dev] [bugs #11396] Large number jumps to hyperspace


From: Russell Shaw
Subject: Re: [avr-libc-dev] [bugs #11396] Large number jumps to hyperspace
Date: Mon, 03 Jan 2005 14:05:13 +1100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Debian/1.7.2-4

Joerg Wunsch wrote:
As Russell Shaw wrote:

uint16_t baud=9600
uint16_t reg=16000000/(16*baud) - 1;

what about __udivmodsi4?

Yeah.  I didn't assume such poor optimization.

In the real code, uint16_t baud was set at 9600 using a const
literal passed as an array parameter.

As Eric just closed the bug report as being unreproducible, I gave it
a try to simulate your example code.  I cannot reproduce any ``jumps
to nowhere'' behaviour though (and thus basically confirm Eric's
judgement).

However, your above example miscalculates `reg', as the expression
``16*baud'' is computed in uint16_t domain but overflows it.  The
result of this subexpression is 153600 but is truncated to 22528.
Maybe this is your problem?

Rewriting the second calculation as:

uint16_t reg=16000000/(16*(unsigned long)baud) - 1;

makes it work for me.

That is the correct way.

> Though this is technically right, I think
most people would prefer

uint16_t reg=16000000UL/(16*(unsigned long)baud) - 1;

instead to make it explicit that the clock frequency is also an
unsigned long (even though the C standard is on your side and you're
permitted to omit the `UL').  Writing the UL suffix is also sufficient
to force the entire expression into the UL domain, so this works, too:

uint16_t reg=16000000UL/(16*baud) - 1;

Won't work. Some languages propagate all the numbers in an expression to
match the largest number first, but C does not.

In 16*baud, 16 and baud are promoted to the default word size "int" of
the machine, then the multiplication performed (in int mode), which can
overflow. Then the result is promoted to UL *after* the multiplication.

I never realized overflow in C like that can happen before, because on a pc,
32 bit ints are much less likely to overflow. Most things with large numbers
on the avr i've done with float or long int.

Still, I'd personally prefer the previous version since it makes it
explicit.  C type promotion rules are often not easy to understand at
a first glance.

See "Integer promotion and overflow" thread on comp.lang.c.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]