View previous topic :: View next topic |
Author |
Message |
s_mack
Joined: 04 Jun 2009 Posts: 107
|
Show me the signs! Signed vs unsigned... when exactly does |
Posted: Sun Sep 06, 2009 4:56 pm |
|
|
Say I have this:
Code: | if ( delta_u_n < (u_min - u_n_1) ) |
if delta_u_n is a signed int but the other two are both unsigned, could I run into a problem? If u_min - u_n_1 produces a negative number but are both unsigned does that mean the result of that little bit of math is still positive? Thereby forcing the statement to always be false if delta_u_n is negative? Or is it implicitly converted to signed at the < first ??
I read the help file regarding this but I'm still not sure.
Thanks. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Sep 07, 2009 1:07 am |
|
|
It's generally a good idea to check the compiler behaviour empirically.
The other interesting question is however, if there's an expected result according to C language rules, and in addition, if CCS C is following the rules in this case. This question is particularly interesting for those, who are working also with other tools besides CCC C.
As far as I know, clear rules exist for the present case, and they are basically identical for K+R and ANSI C:
- implicite type conversion applies for relational operators
- when signed and unsigned operands of same word length are used together, the signed operand shall be converted to unsigned
This expected behaviour can be found with full featured C compilers, e.g. from Microsoft or Borland.
As far as I see, CCS C is following different "rules". With PCH, the compare is performed without implicite type conversion. Thus when comparing an unsigned with a negative signed value, the negative value is always regarded smaller. This result may be expected by common sense, but is not according to C rules.
With PCD, an implicite type conversion from unsigned to signed is performed, also contradicting usual C rules.
As a result, explicite type conversions should be used with CCS C in mixed type expressions to clarify your intentions. It doesn't harm with other C compilers anyway.
Code: | if ( delta_u_n < (signed int16)(u_min - u_n_1) ) |
|
|
![](templates/subSilver/images/spacer.gif) |
s_mack
Joined: 04 Jun 2009 Posts: 107
|
|
Posted: Mon Sep 07, 2009 1:11 am |
|
|
Thanks! |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Mon Sep 07, 2009 3:17 am |
|
|
The difference here, is actually in the C language!...
If you read A6.5, in K&R, the 'rules' for converting signed/unsigned, depend on whether the 'signed' type, can represent all values contained in an unsigned type:
"The effect depends on whether a long int can represent all values of an unsigned int; If so, the unsigned int, is converted to long int; If not, both are converted to unsigned long int.".
So, Given that the signed type in CCS, only has 15 bits for the actual value, CCS is correct to convert both values to unsigned, and compare with these.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Sep 07, 2009 4:15 am |
|
|
In my opinion, the K&R remark on unsigned short to long int conversion only applies, when long int is one of the involved types. It isn't in the present case. So the general rule of converting to unsigned (unsigned int16 in this case) applies. In my understanding the ANSI C type conversion rules are basically telling the same, but I'm not very familiar to it.
So if PCH would use general C conversion rules, an explicite typecast to signed int16 is necessary to achieve the intended behaviour.
The other point is, that according to my test, neither PCH nor PCD (V4.099) are following the rule. But the typecast is correct for CCS C anyway. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Mon Sep 07, 2009 5:05 am |
|
|
I don't agree.
The very next line says:
"Otherwise if either operand is unsigned int, the other is converted to unsigned int.".
What is left unsaid, is 'how' the conversion should be done....
For myself, the best way to work, is to be completely 'explicit' in your testing, and not assume anything about the language. So if comparing signed, with unsigned, test your signed value for being less than zero, and do your own handling of this potential 'overflow' situation, or explicitly use a larger type.
Best Wsihes |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Sep 07, 2009 8:50 am |
|
|
Quote: | What is left unsaid, is 'how' the conversion should be done.... |
In my K&R version, it's defined as 2^nbit modulo operation, in other words taking the signed bitvector as unsigned. That's also, what most C compilers do.
But I completely agree to your conclusion, that explicite typcasting is the preferable, safe method. |
|
![](templates/subSilver/images/spacer.gif) |
s_mack
Joined: 04 Jun 2009 Posts: 107
|
|
Posted: Mon Sep 07, 2009 11:23 am |
|
|
i understand that it is best to just be explicit. The problem I see is the extra logic required to handle potential overflow adds to the program size and we're working in embedded applications with almost necessarily finite ROM. So understanding how "shortcuts" may work can be critical to reducing the size.
In my case this time, what happened was because of the math involved I needed a ton of code to account for the various overflow possibiities. In the end it was more efficient to eliminate all that and use all signed int32 instead. This seemed very unfortunate because I spent a lot of effort converting all my floats to int16 only to have them be int32 just because of signs kind of sucked. |
|
![](templates/subSilver/images/spacer.gif) |
s_mack
Joined: 04 Jun 2009 Posts: 107
|
|
Posted: Mon Sep 07, 2009 12:35 pm |
|
|
Somewhat unrelated (nothing to do with signs)
Code: | pedal_output = (int8)(( pedal_setting + 64 ) >> 7); |
Assume pedal_setting is an int16 and pedal_output is an int8. "when" does the typecast happen? Is it at assignement or before the math? Should I just leave the int8 out and let the = handle that?
The intent here is to add 64 to my int16 value then divide that by 128 (which by previous math guarantees it is < 255) and assign the result as an int8 to pedal_output.
Have I done it right? Or should it be more (or less?) explicit? |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Sep 07, 2009 1:24 pm |
|
|
I think, it's O.K. this way.
The brackets specify to apply the (int8) typecast after all arithmetic, which is obviously intended. It shouldn't be necessary because the assignement to an int8 variable basically does the same. However some compilers issue warnings about possibly lost bits in assignment and the type cast would be an appropriate means to suppress the warning.
I experienced a curiosity with CCS C, that type casts sometimes involve generation of additional (meaningless) code. If you are short on resources, you may want to check the impact of this constructs on code size. |
|
![](templates/subSilver/images/spacer.gif) |
|