Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Can anyone explain this C18 feature/bug?

Status
Not open for further replies.

Pommie

Well-Known Member
Most Helpful Member
I had a bug in some code and finally tracked it down to this bit of code,
**broken link removed**

Can anyone explain how 4*60*6 = -96?

This is one of the reasons I really distrust C18.

Edit, Actually, I just worked it out. It's done the calculation as bytes to get 160 (1440-5*256) and then cast this to a signed byte before casting to my signed long. Someone should be shot for that. I knew there was a reason I stopped using C18.

Mike.
 
Last edited:
Out of interest.... What do you use now.... I have had MAJOR issues with constant arrays... bytes missing causing misalignment.... arithmetic errors... sometimes hard to track down.

I tried Hi-tech but that also has issues.
 
Maybe more of a feature.

Constant expressions evaluation is done at compile time. If we give the compiler a bit of help it will generate the correct results.

delay = (long) 4*60*6;

I expect if you had been working with a 16 or 32 bit C compiler the default data size for doing these constant expressions would be larger. Not 100% sure. Has anyone found a reference to this in the standards?

I am thinking of condensing this an adding it to the sticky when it is fully sorted.
 
From the users guide: https://www.electro-tech-online.com/custompdfs/2012/03/51288f.pdf

Code:
2.7.1 Integer Promotions
ISO mandates that all arithmetic be performed at int precision or greater. By default,
MPLAB C18 will perform arithmetic at the size of the largest operand, even if both
operands are smaller than an int. The ISO mandated behavior can be instated via the
-Oi command-line option.
For example:
unsigned char a, b;
unsigned i;
a = b = 0x80;
i = a + b; /* ISO requires that i == 0x100, but in C18 i == 0 */
Note that this divergence also applies to constant literals. The chosen type for constant
literals is the first one from the appropriate group that can represent the value of the
constant without overflow.


Purely from the standpoint of optimization C18 usually can be trusted to stick with 8 bit operations when given 8 bit constants. I assume unless I tell it explicitly it will default to 8bit. We all do it (and regret it later) but this is a good example of why it's bad practice to use values instead of defines in code.

When you define a value you can also give it a data type.
#define C_BBB 60uc // defined as a unsigned char value 60
#define C_XXX 60l // defined as a long type value 60
#define C_YYY 60ul // defined as a unsigned long type value 60
 
  • Like
Reactions: 3v0
Why would you make constants 8 bit when they are calculated at compile time? There is no optimisation. The code gets no more efficient. Just wrong.

Mike.
 
nsaspook +1

what is not standard is also the definition of int, int should be define has the size of data that is usual for the uController.
so it should be define has 8bits (char) , but it is in fact it is define has 16bits (short)

so for ex.
int i;
for ( i = 0; i < 10; i++) ...

is bad cause it take 2 memory read to read "i". 2 memory writes to write it and of course to many cpu cycles ...
on standard compiler int i should have been read in one access ... etc

:)
 
Last edited:
I had a bug in some code and finally tracked it down to this bit of code,
**broken link removed**

Can anyone explain how 4*60*6 = -96?
...

I can explain it Pommie, it happens becuase the guys who wrote the preprocessor deserve to be shot. ;)

There is no - sign expressed in your constant expression 4*60*6 so it should always be proprocessed to the a single positive value 1440. Then that positive value should be assigned to your signed long variable.

No excuses, no exceptions, no hiding behind ISO bulldust. Get a better compiler!

MikroC does it right;
Code:
;Led_Blinking.c,26 :: 	del = 4*60*6;
$0004	$30A0		MOVLW	160
$0005	$1303		BCF	STATUS, RP1
$0006	$1283		BCF	STATUS, RP0
$0007	$00A0		MOVWF	_del
$0008	$3005		MOVLW	5
$0009	$00A1		MOVWF	_del+1
$000A$01A2		CLRF	_del+2
$000B	$01A3		CLRF	_del+3

And the hardware libraries with MikroC PRO are getting VERY impressive now, it just grows in massive leaps each year. :)
 
Last edited:
If it's documented it's not a bug but a feature that can be used. :) http://thetaeng.com/TimerWrap.htm

You can make something with a really bad mistake, that performns really badly, that creates a fault that nobody in their right mind would expect, and then "document" it.

Like a power station that blows up if it rains and the wind blows at the same time. "But it was documented!"...

Or a guy that drives his car all over the neighborhoods kids. "But I documented that I couldn't see small objects in front of my car!"...

It's still a fault, a mistake, an error, bad design, wrong, no matter what fashionable label they want put on it.

In this case the compiler allows 32bit variables, it knew the variable was 32bit signed long, and it knew the user wanted to store this positive number (4*60*6) into the signed long variable. There is just no excuse for it failing so terribly.
 
Last edited:
In this case the compiler allows 32bit variables, it knew the variable was 32bit signed long, and it knew the user wanted to store this positive number (4*60*6) into the signed long variable. There is just no excuse for it failing so terribly.

Different strokes for different folks.

Integer promotion:

The integer promotion rules of ANSI C are probably the most heinous crime committed against those of us who labor in the 8-bit world.

https://www.barrgroup.com/Embedded-Systems/How-To/Efficient-C-Code
 
Nobody said we have to obey really bad rules. That's why we have things like analysis, development, evolution, improvement etc.

Like I said, MikroC gets it right. :)
 
Integer promotion rules should only apply to the machine where the calculation is being performed. In this case the calculation is being done on a PC which has an integer size of 32 bits. Hiding behind some absurd argument that it is some kind of optimization is simply a lie.

Mike.
 
Two for undecided on FEATURE or BUG. ;)
 
So you think they coded it correctly, so it's working in the best way, and it should not be improved?

The underlying issue is much larger then constant expression evaluation.

We need a C standard dedicated to microcontrollers. As I understand it the MISRA standard, used by the automotive people, comes closer then other existing standards.

Along the same line I would like to see microcontroller vendors provide the processor header files to compiler vendors!

In a very real sense the 'easier to use' MikroC and CCS are problematic. If one uses their proprietary features the code is difficult to debug or port. The lack of portability is massive compared to C18's inconvenient but historically correct feature.
 
The lack of portability is massive compared to C18's inconvenient but historically correct feature.

I really don't agree with the "correct" statement. The "default to processor size" should not (and does not, except C18) apply to constants. I should be able to write any combination of constants and it should be right.

I really don't understand why anyone is defending this!!! Please find another compiler that treats constants this way?

It's just plain wrong.

23*47=? C18 thinks it's 57!!! Can anyone find another compliant compiler that agrees? Surely if it is the inconvenient standard then there should be lots of examples out there.

Mike.
 
I get it that you feel it is logically wrong.

Can you point any documentation that supports
I should be able to write any combination of constants and it should be right.

I have run into this with other embedded compilers. But I do not recall which. Yeah not exactly solid evidence.

I would rather that it work differently too. But I am not overly upset to find that it does not.

Having said that it is documented and there is a mechanism in place to make it use 16 bits. Not exactly a show stopper.
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top