Searching \ for 'CCS - Conversions between different types' in subject line. ()
Help us get a faster server
FAQ page: techref.massmind.org/techref/index.htm?key=ccs+conversions
Search entire site for: 'CCS - Conversions between different types'.

Truncated match.
'CCS - Conversions between different types'
1999\04\09@100901 by

I'm trying to figger out what will happen when I mix Signed Long and regular
Long types under CCS, like this

long a;
long b;
signed long s;

b = 1000;
a = 500;

s = b - a;

I assume S is supposed to be a negative number now  (- 500 decimal)

if (S < 0)
subroutine1();

Will it  then execute subroutine1 Like I think it should?

then if I do:

b = s;   //   Don't try this at home - warning type conversion

It should make a mess out of B,  it should be 65536 - 500 = 65036 decimal,
no?

Lyle,

This is really a C question, but its specific to this implementation.
> long a;
> long b;
> signed long s;
in CCS "long" is an unsigned long, CONTRARY TO THE C STANDARD,
where by default, integers are signed unless declared otherwise.

"unsigned long" is always the unsigned type.

> b = 1000;
> a = 500;
>
> s = b - a;
>
> I assume S is supposed to be a negative number now  (- 500 decimal)
Uh... 1000 - 500 is 500.

I think you mean a - b, which is more interesting.

Since a and b are unsigned, the expression a - b is also unsigned,
and since this is an "underflow", you get the result that:
500 - 1000 = 65036
because what the machine did was:
01F4 - 03E8 = FE0C (plus a borrow out, which is discarded)

But, since CCS uses two's complement format for signed integers, the
bit pattern in the result is the same for signed or unsigned.  (I
suspect the code is the same, too.)

The assignment then makes an implicit cast of the unsigned result
to a signed number.  I don't know for sure how CCS interprets that
cast.  A test program is the best way to find out; on most
implementations, the result should be the same bit pattern, so the
result should be -500.

I will not repeat my past rant about how I no longer trust this
compiler.  Your milage may vary; again, a quick test program will
tell you.

>
> if (S < 0)
>        subroutine1();
>
> Will it  then execute subroutine1 Like I think it should?
I predict it will.

>
> then if I do:
>
> b = s;   //   Don't try this at home - warning type conversion

Again, this is a cast, this time from signed to unsigned.  The
interpretation is likely a direct copy, so the bit pattern is
preserved.  So now if b = s = a-b, b is 65036.

> It should make a mess out of B,  it should be 65536 - 500 = 65036 decimal,
> no?
Yes.  Its not a mess exactly- its predictable, but it might not be
what you meant.  That's what the warning means.

So... in practice, make the casts explicit, so that your intent is
clear.  If you WANT to assign a signed to and unsigned, do:

b = (unsigned)s;

Which makes the same code, but makes it clear you did the
conversion on purpose and are prepared to take the consequences :)
The compiler shouldn't warn you anymore.

Hope this helps,

Regards,

------------
Barry King
Engineering Manager
NRG Systems "Measuring the Wind's Energy"
barrynrgsystems.com
Phone: 802-482-2255
FAX:   802-482-2272

Thanks to Barry King for a good explanation!

OOps  I made a goof -

-----Original Message-----
From: Lawrence Lile <lilelTOASTMASTER.COM>
To: PICLISTMITVMA.MIT.EDU <PICLISTMITVMA.MIT.EDU>
Date: Friday, April 09, 1999 9:09 AM
Subject: CCS - Conversions between different types

>I'm trying to figger out what will happen when I mix Signed Long and
regular
{Quote hidden}

I meant to say a-b

{Quote hidden}

Comment is mine- I always put comments in my code when something un-obvious
might be going on

>It should make a mess out of B,  it should be 65536 - 500 = 65036 decimal,
>no?

|I will not repeat my past rant about how I no longer trust this
|compiler.  Your milage may vary; again, a quick test program will
|tell you.

I have found that I get consistent results with the CCS compiler when
I use only unsigned types, ensure that any subexpression which may pro-
duce a 16-bit result has at least one term cast as 'long', don't pass
array elements by reference, and don't let the program or data storage
usage get too big (I hand-place selected arrays, etc. in the second bank
if need be to avoid 'normal' variables or temporaries from going there).

Supposedly, the CCS compiler supports floating point and signed math, but
I know that initially their signed-math support was quirky; I don't know
if it's improved.

Despite its limitations, the CCS compiler is often much nicer than using
straight assembly; I do not doubt that HiTech and ByteCraft have better
products, but the CCS compiler is nonetheless a useful product if you can
get used to its quirks.

BTW, I've *NEVER* been bitten by a Pascal or C compiler bug for the 8x88
(using Borland products).  I've *ONCE* been bitten by a compiler bug for
the Motorola 68000.  I wonder why it's so hard for compilers to produce
*CORRECT* code on the PIC?

The 68000 compiler bug was in MPW C.  While stack frames are normally lim-
mitted to 32K, there was a newly-added compiler switch which was supposed
to get around this.  When it was not possible to use address (A6+disp)
because 'disp' was >32K, the compiler would instead generate code like:

move.l  a6,a0                   ; Destination is a0!
add.l   #disp,a0                ; 'disp' may be 32 bits
dostuff (a0),???                ; A0 has the correct address

It did this consistently for all places where the code would have nomally
used the (A6+disp) mode.  Everything in the code was perfect, in fact,
except for one thing: to update the stack pointer at the end of the rou-
tine, the compiler generated a *16-bit* add.  Interestingly, however, this
did not cause a crash because the system later loaded the stack pointer
from the frame pointer.  The contents, however, of the registers that were
saved on the stack when the routine entered were loaded from the wrong
place.  Thus, while the software returned to the right spot, some regist-
ers got unexpectedly trashed.

What made this bug particularly hard for me to find was that the 'import-
ant' register that got trashed happened to be holding a constant.  While
the debugger knows during what parts of the code local variables are held
in registers (and if the PC is in such a part, displaying the variable
will show the register) it does not track constants the same way.  This
caused particular annoyance when I tried printing the address of an array;
within the debugger, the address would print correctly but in my program
it would sometimes not.  It turned out the compiler was keeping that add-
ress in a register and thus the program malfunctioned when that address
got munged.

Oddly, the next version of the compiler solved the problem for routines
whose local stack frame was >64K.  But if it was between 32K-64K, the same
problem occured; the compiler apparently did not realize that the 16-bit