![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
#define and multiplication in a "if" statement |
Posted: Mon Sep 15, 2014 8:45 am |
|
|
Me and #define's again
Am I doing something wrong or maybe compiler bug?
When I multiple two constants in a if for comparison the result seems wrong.
If I assign the multiplication to a Temp and then compare with the temp everything seems to be OK.
Code: |
#define I_IN_MULT (1937)
#define CHARGER_CAPACITY (12)
.................... if (IinADC > (CHARGER_CAPACITY * ILIM_MULT_IN)) {
017BE: MOV 1008,W0
017C0: CLR W3
017C2: BTSC W0.F
017C4: SETM W3
017C6: MOV W3,W1
017C8: MOV W3,W2
017CA: CALL 1442
017CE: MOV W0,W4
017D0: MOV W1,W5
017D2: MOV W2,W6
017D4: MOV W3,W7
017D6: MOV #A105,W0
017D8: MOV #D900,W1
017DA: MOV #6D71,W2
017DC: MOV #4082,W3
017DE: CALL 14A6
017E2: BRA NC,17FE
.................... Temp = CHARGER_CAPACITY * ILIM_MULT_IN;
017E4: MOV #24D,W4
017E6: MOV W4,1032
.................... if (IinADC > (Temp)) {
017E8: MOV 1032,W0
017EA: MOV 1008,W4
017EC: CP W4,W0
017EE: BRA LE,17FE
.................... |
CCS 5.025 (PCD)
dsPIC33EP28GM604
Regards |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Sep 15, 2014 8:56 am |
|
|
have you tried the #define without the () ??
defining a new CONST that is
CHARGER_CAPACITY * ILIM_MULT
so you don't call for the mult every compare ? |
|
![](templates/subSilver/images/spacer.gif) |
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Mon Sep 15, 2014 9:06 am |
|
|
Feel like an idiot now. I asked this question a couple of months ago and complete forgot.
You have to cast the constant and then it works.
Sorry for wasting your time asmboy. |
|
![](templates/subSilver/images/spacer.gif) |
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Mon Sep 15, 2014 9:09 am |
|
|
checkout the function:
may save headaches and code space |
|
![](templates/subSilver/images/spacer.gif) |
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Mon Sep 15, 2014 9:32 am |
|
|
The thing is, it is a multiplication of constants, so the compiler should take care of it when compiling and does so correctly if you just cast it.
Agree on the _mul() though , works like a charm, neat piece of code from CCS.
Regards |
|
![](templates/subSilver/images/spacer.gif) |
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Sep 15, 2014 9:51 am |
|
|
Hi,
I've been keeping some informal statistics, and here is what I've found:
When a forum user says this:
Quote: |
maybe compiler bug?
|
In 97.6% of the cases, it turns out to actually be a 'user bug'
John |
|
![](templates/subSilver/images/spacer.gif) |
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Mon Sep 15, 2014 10:23 am |
|
|
Agree on that ezflyr.
But then this should also be treated by the compiler everywhere the same.
E.g
if (Var > (CONST1 * CONST2)) then. Does do funny things.
MyFunc(Var, CONST1 * CONST2). Passes the correct val to the function.
BTW, just casting all of my CONST reduce the code space by about 1.5kB ![Very Happy](images/smiles/icon_biggrin.gif) |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Sep 16, 2014 2:01 am |
|
|
alan wrote: |
But then this should also be treated by the compiler everywhere the same.
E.g
if (Var > (CONST1 * CONST2)) then. Does do funny things.
MyFunc(Var, CONST1 * CONST2). Passes the correct val to the function.
BTW, just casting all of my CONST reduce the code space by about 1.5kB ![Very Happy](images/smiles/icon_biggrin.gif) |
In C literals have no implied type nor size. The compiler doesn't know whether to use 8, 16 or even 32 bit arithmetic with them, they are just numbers. In fact with #define they are just text.
It is the context in which they are used which tells the compiler what arithmetic type to use. If you compare it to an int8 variable it will use int8 arithmetic, if you pass it to a subroutine which wants an int16 parameter it will get treated as 16 bit. The results may well be different. Casting forces a type on the literal at the point of use, which is why it makes it work. You could put the type in the #define, either with a cast or with the type specifiers: l, ul, u, f, etc. However these do not give the full range of compiler specific types and can be confusing and not very portably as precisely what they mean is compiler dependant. Think about the difference between CCS C's idea of what int is compared to most PC Cs.
The designers of later languages, including C-based such as C++ and C#, realised this very weak typing was a problem and so introduced the concept of stronger typed constants. Later, these were taken back in to C, e.g. ANSI C, with const, but the old "#define" way of doing things lived on.
If your CONSTs really are declared as consts then you'll have fewer of these sorts of problems. If they are #defined, then they are NOT really consts, and are not typed and so confusing stuff may happen. |
|
![](templates/subSilver/images/spacer.gif) |
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Tue Sep 16, 2014 2:36 am |
|
|
So if I understand you correctly RF_Developer it is better to define a 'const' instead of #define when using it to calculate.
Thus
Code: | #define SYNC_I ((uint16_t) (I_CHRG_MULT *2 / 95)) |
becomes
Code: | const uint16_t SYNC_I = (I_CHRG_MULT *2 / 95); |
with no memory penalties.
Regards |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Sep 16, 2014 4:18 am |
|
|
alan wrote: | it is better to define a 'const' instead of #define when using it to calculate.
Thus
Code: | #define SYNC_I ((uint16_t) (I_CHRG_MULT *2 / 95)) |
becomes
Code: | const uint16_t SYNC_I = (I_CHRG_MULT *2 / 95); |
with no memory penalties. |
Const is the newer way. Whether it is always "better" depends on your point of view. Using const doesn't necessarily mean you don't have to cast, especially where the value being assigned to has a different type to that used for the arithmetic. The strong typing in C++ and C# forces the programmer to explicitly cast whereas in C its often done implicitly/automatically which often causes problems, particularly when the programmer makes incorrect assumptions about what will happen.
Whether there is a memory impact is an issue that's not easy to predict. All things considered, consts may produce more compact, but possibly slower code.
Really const is a specifying that a variable is constant, which acts to the compiler as a hint/flag that it can store it in non-volatile memory if its available, and to not allow write access to the const variable if it isn't. In PICs such consts can be stored in program memory rather than ram, but that carries the price of slower access. However a literal is always stored in program memory and very often inline in the code.
Literals that are used several times in the same code will probably be stored several times rather than being stored once as you would expect with const. Also literals may well use different code to access than const, but the CCS compiler seems to be pretty canny in this. I did a simple trial, compiled for an 18F66K80, and the #define and const versions produced essentially identical code.
When using const, the compiler may not be able to collapse constant expressions as easily with const as with literals. Constant collapse is where the complier does arithmetic on expressions that have a constant result, i.e. are made up from simple mathematical operations on constants. However, as C uses functions to implement many mathematical operations, particularly with floating point, few compilers are able to collapse constant expressions that have C functions such as log10() and atan(), which is inconvenient - you have to pre-compute such expressions yourself.
As a historical note, there were once many computers that did not even have an immediate addressing mode, needed for accessing literal/constants inline. These simply allocated constants to ram and just didn't write to them. Many machines had basic constants, sometimes simple 0 and 1, wired as read-only memory locations for easy access. Thankfully we don't have to deal with that on PICs.
So, there are some complexities with #define vs const. To be honest I still use #defines with C, but use consts for C++ and C#. You have to for C# as it doesn't have a pre-processor, and therefore doesn't have #define.
|
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|