CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

#define and multiplication in a "if" statement

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

#define and multiplication in a "if" statement
PostPosted: Mon Sep 15, 2014 8:45 am     Reply with quote

Me and #define's again Evil or Very Mad Mad

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
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Sep 15, 2014 8:56 am     Reply with quote

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 ?
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Mon Sep 15, 2014 9:06 am     Reply with quote

Feel like an idiot Embarassed now. I asked this question a couple of months ago and complete forgot.
You have to cast the Evil or Very Mad constant and then it works.

Sorry for wasting your time asmboy.
stinky



Joined: 05 Mar 2012
Posts: 99
Location: Central Illinois

View user's profile Send private message

PostPosted: Mon Sep 15, 2014 9:09 am     Reply with quote

checkout the function:
Code:
 _mul(val1, val2)


may save headaches and code space
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Mon Sep 15, 2014 9:32 am     Reply with quote

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
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Mon Sep 15, 2014 9:51 am     Reply with quote

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' Laughing

John
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Mon Sep 15, 2014 10:23 am     Reply with quote

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
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Sep 16, 2014 2:01 am     Reply with quote

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


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.
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Tue Sep 16, 2014 2:36 am     Reply with quote

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
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Sep 16, 2014 4:18 am     Reply with quote

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.



Code:
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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