'CCS - Conversions between different types'
I'm trying to figger out what will happen when I mix Signed Long and regular
Long types under CCS, like this
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)
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,
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
> if (S < 0)
> 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,
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,
NRG Systems "Measuring the Wind's Energy"
Thanks to Barry King for a good explanation!
OOps I made a goof -
From: Lawrence Lile <TOASTMASTER.COM> lilel
To: MITVMA.MIT.EDU < PICLISTMITVMA.MIT.EDU> PICLIST
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
I meant to say a-b
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,
|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
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
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
add instruction uses SIGNED arithmetic if the destination is an address
register (so, e.g., "add.w #65535,a0" will [if the assembler doesn't rej-
ect it] actually be interpreted as "add.w #(-1),a0" and subtract one from
More... (looser matching)
- Last day of these posts
- In 1999
, 2000 only
- New search...