• AVR Freaks

Helpful ReplyLockedPreprocessor calculation of constants

Author
jhendrix
New Member
  • Total Posts : 10
  • Reward points : 0
  • Joined: 2012/10/22 00:54:02
  • Location: 0
  • Status: offline
2012/12/17 14:56:55 (permalink)
0

Preprocessor calculation of constants

I'm having trouble with a #defined value evaluating to 0.  Here is the code
 
#define a 14700
#define b 250
#define c 1024
 
#define d ((b * c)/a)
 
By my calculation, this should result in d = 17.  But I can see from the assembly that it evaluated to 0.  Any suggestions?  Is it because the numbers are too large?  It seems like the preprocessor should evaluate the calculation before deciding if the values are too large.
 
I'm using MPLAB X IDE, with the XC8 compiler version 1.1.  I'm compiling for the PIC16F1827.  
#1
Ian.M
Super Member
  • Total Posts : 13225
  • Reward points : 0
  • Joined: 2009/07/23 07:02:40
  • Location: UK
  • Status: offline
Re:Preprocessor calculation of constants 2012/12/17 15:10:35 (permalink)
+2 (1)
How are you using d?
 
Remember, the preprocessor ONLY evaluates expressions in the #if directive.  The rest of the time it performs simple textual substitution so your set of #defines are equivalent (for d) to
     #define d ((250 * 1024)/14700)
not
     #define d 17
 
 
post edited by Ian.M - 2012/12/17 15:11:58
#2
jhendrix
New Member
  • Total Posts : 10
  • Reward points : 0
  • Joined: 2012/10/22 00:54:02
  • Location: 0
  • Status: offline
Re:Preprocessor calculation of constants 2012/12/17 15:29:37 (permalink)
0
I must be a little confused about where it gets done, but I expected that equation to get reduced to a constant, which it apparently does (to 0).   I suppose that's being done in the compiler.   I also expected that calculation to be done at the host level i.e. 32-bit data.
 
I'm using d as follows:
 
uint16_t r_bat = adcVal;
 
if(rbat > l_bat + d)
{
  /* switch battery */
}
#3
rusttree
Super Member
  • Total Posts : 910
  • Reward points : 0
  • Joined: 2010/06/14 14:10:14
  • Location: Phoenix, AZ
  • Status: offline
Re:Preprocessor calculation of constants 2012/12/17 15:33:52 (permalink)
0

uint16_t r_bat = adcVal; 
  
if(rbat > l_bat + d) 

Is that just a transcription error or did you copy-paste that right out of your code?  If it's the latter, you've got a typo that might be the source of problems ("r_bat" vs. "rbat").
#4
jhendrix
New Member
  • Total Posts : 10
  • Reward points : 0
  • Joined: 2012/10/22 00:54:02
  • Location: 0
  • Status: offline
Re:Preprocessor calculation of constants 2012/12/17 15:47:02 (permalink)
0
That's psuedo code - I'm not co-located with the actual code at this moment.  By the way, in addition to inspecting the assembly and seeing a zero being moved into the register, I also added debug code like this:
 
r_bat = d;
 
Then, examing r_bat in the debugger, I could see it's value was 0.
-Jason
#5
Ian.M
Super Member
  • Total Posts : 13225
  • Reward points : 0
  • Joined: 2009/07/23 07:02:40
  • Location: UK
  • Status: offline
Re:Preprocessor calculation of constants 2012/12/17 15:48:52 (permalink) ☄ Helpful
+3 (2)
Preprocessor evaluation is 32 bit, but the compiler's compilation phase will default to evaluating the expression as a signed integer (as specified by the ANSI C89 standard) unless it has already been forced to promote it due to some other part of it.  If the variable l_bat is also uint16_t it *may* be using 16 bit unsigned maths, but I would have thought the parentheses () isolate it from promotion and it would still overflow.   Evaluating it as a signed integer with 16 bit word length in my favourite RPN calulator app's Comp Sci mode gives an overflow for the multiplication to Zero . . . sad (not surprising when you multiply a value >255 by 256 mr green)
 
A couple of casts should fix it:
    #define d (uint16_t)(((uint_32_t)b * c)/a)
post edited by Ian.M - 2012/12/17 15:57:29
#6
NKurzman
A Guy on the Net
  • Total Posts : 17720
  • Reward points : 0
  • Joined: 2008/01/16 19:33:48
  • Location: 0
  • Status: online
Re:Preprocessor calculation of constants 2012/12/17 16:37:51 (permalink) ☄ Helpful
+2 (3)
OR
#define a 14700UL
#define b 250UL
#define c 1024UL
#7
jhendrix
New Member
  • Total Posts : 10
  • Reward points : 0
  • Joined: 2012/10/22 00:54:02
  • Location: 0
  • Status: offline
Re:Preprocessor calculation of constants 2012/12/17 16:48:22 (permalink)
0
Good stuff.  I will try this when I get home.
#8
jhendrix
New Member
  • Total Posts : 10
  • Reward points : 0
  • Joined: 2012/10/22 00:54:02
  • Location: 0
  • Status: offline
Re:Preprocessor calculation of constants 2012/12/17 22:24:58 (permalink)
0
This fixed the problem, thanks a lot for your help and quick response.
#9
Jump to:
© 2019 APG vNext Commercial Version 4.5