![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
DireSpume
Joined: 07 Jan 2013 Posts: 31
|
Function overloading doesn't work |
Posted: Mon Jan 14, 2013 3:59 pm |
|
|
I am using the PCH compiler version 4.140 for a PIC18F67K22.
The following code has two versions of NTimeSet(). Notice in main() that I am calling the second version of NTimeSet(), with the uint32_t argument. However, upon execution, it turns out that the first version (with the NTime* argument) is what is actually being called. Oddly enough, it doesn't crash when the pointer is dereferenced. Anyway, if I reverse the order in which the two functions are defined, it does then call the correct function. CCS claims to support function overloading, but this would seem to demonstrate that function overloading is NOT supported. What am I missing?
Code: |
typedef struct {
uint32_t Ms;
uint32_t Of;
} NTime;
void NTimeSet(NTime* ntime, NTime* pnew) {
printf("In NTime version\r\n");
*ntime = *pnew;
}
void NTimeSet(NTime* ntime, uint32_t micros) {
printf("In uint32_t version\r\n");
ntime->Ms = micros;
ntime->Of = 0;
}
void main() {
NTime t;
NTimeSet(&t, (uint32_t)20000);
while (TRUE) {
output_high(PIN_B6);
delay_ms(500);
output_low(PIN_B6);
delay_ms(500);
}
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jan 14, 2013 7:31 pm |
|
|
Your example fails for me too. But then I played around with it a bit
and it works if you declare the passed variable on a separate line
before you use it. Example of how to make it work:
Quote: |
void main() {
NTime t;
uint32_t temp;
temp = 20000;
NTimeSet(&t, temp);
|
|
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Jan 15, 2013 2:53 am |
|
|
There are two things that spring to mind. First CCS C is NOT case sensitive by default, unlike many other C compilers. Therefore "NTime* ntime" is the same as "NTime* NTime" and it will confuse the type and the variable, leading to unpredictable errors. Its always wise to differentiate types and variables, some people use "_t" to indicate a type, as in "NTime_t* ntime" and, arguably oddly as unit32 is already a defined type in CCS C in unit32_t. There are many other ways of indicating a type.
The second possible problem is that overloading is NOT a normal part of C, and as far as I can see, was primarily implemented by CCS to facilitate their own library code, particularly the math code, which uses overloading to implement different typed overloads of the functions. As such it MAY, and only may, be that overloading is not fully implemented and tested for all types, only for those which CCS use in their libraries. It is known that some compiler issues have had trouble with some overloading. I do not know which compiler versions were affected.
I suggest only using overloading if you MUST, i.e. there is no other way to implement the functionality, rather than because you can. Its not part of C and will create unportable and difficult to maintain code (because other programmers will not expect C to have overloads and not recognise them as such).
RF Developer |
|
![](templates/subSilver/images/spacer.gif) |
DireSpume
Joined: 07 Jan 2013 Posts: 31
|
|
Posted: Tue Jan 15, 2013 2:45 pm |
|
|
Thanks for the helpful responses. You are quite right about the problem of the compiler not being case sensitive -- a truly silly aspect of this compiler that I had to learn the hard way. But fixing that had no effect on the problem. I also tried passing pnew by value instead of by address, but it still called that function instead of the uint32 one. But as PCM programmer pointed out, it calls the correct function if you pass a variable instead of a constant. Regardless, the take-away is that function overloading IS NOT a compiler feature that has been fully implemented, and therefore it should not be used, and IMO is not a feature that CCS should be advertising. Enough said. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19364
|
|
Posted: Tue Jan 15, 2013 4:01 pm |
|
|
It is actually 'quite interesting', since it throws significant light on how CCS treats variables versus constants. It appears that constants, do not have the flag set to say they are not pointers. The overload requires the second value to be a 'non pointer', to select the second routine, defaulting to the first, if it does not find a match. The cast changes the actual size used for the value (if you test with routines that want int16, versus int32).
It is the pointer versus non pointer test, that isn't working on a constant.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
DireSpume
Joined: 07 Jan 2013 Posts: 31
|
|
Posted: Tue Jan 15, 2013 4:37 pm |
|
|
Well, actually, Ttelmah, I think it's worse than just not being able to differentiate a constant from a pointer address. Because, remember, I tried passing the second NTime argument (pnew) by value instead of as a pointer, and it still got called. I have no idea what the value of pnew would end up being in that case, with 20000 as the argument, but this is clearly not something the compiler should be doing! But it's easy enough to avoid by not trying to overload functions; I've learned my lesson. It's almost as dumb as a C compiler that isn't case sensitive. ![Rolling Eyes](images/smiles/icon_rolleyes.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19364
|
|
Posted: Wed Jan 16, 2013 1:41 am |
|
|
CCS say in the manual, that 'by value' is _limited_ in functionality. I'd avoid it, unless you are using it in it's simplest form.
If you test using two functions that accept an int16, and an int32, rather than a pointer, then use a constant, it works correctly, if you cast the constant as int32, or int16, merrily switching between the functions, but if one of the functions requires a pointer, it instead 'defaults', picking the first function defined, however you cast the constant.
'Pointerness', appears to not have any meaning to a constant, even if you try to cast it in, or away.
As I said, it is an 'insight' into how CCS handles numbers, since with the variable, you can switch merrily using the cast.
It appears that a constant tests as 'true' for being a pointer, whatever you cast, but also tests as 'true' for not being a pointer whatever you cast!.
The compiler is case sensitive, just not by default....
It dates from the origins of CCS, where they were trying to produce a compiler for simple code, and perhaps appeal to people using interpreters on the PIC, such as BASIC, which are normally not case sensitive. They therefore opted to appeal to this market and choose case insensitivity as the default. Just like setting the fuses in the header for your project, just get 'habitual', and set #case.
I've in fact played a trick with a text editor. I dislike the #nolist option that sits at the start of all the processor define files, since it often makes debugging very hard. So I asked a test editor, that can open 'all files' in a directory, to do a search and replace, replacing #nolist, with #case. Makes things much more useable...
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Wed Jan 16, 2013 2:40 am |
|
|
Constants on PICs (at least the PICs CCS C supports) are fundamentally different to variables due to the Harvard architechture of all PICs other than the top end 32s which CCS C doesn't support. CCS C has significant limitations on pointers to constants is all situations, not just in overloading. Its not at all surprising to me that pointerness and constants don't mix well. Its certainly true that a pointer to a variable and a pointer to a constant are quite different beasts as variables and constants are held in a totally different address space, in different memories in fact. CCS C would have to emulate pointer access to a constant by some combination of copying the constant to data space from instruction space and them forming a temporary pointer to it. CCS C may do this with this directive:
Code: |
#device CONST=READ_ONLY
|
Which stores constants in data memory, but with compiler enforced read-onlyness, and for strings:
Code: |
#device PASS_STRINGS=IN_RAM
|
Which causes constants strings to be copied to ram before being passed as parameters to routines.
I don't regard the case-sensitivity as "dumb" or "silly". I regard an expectation that all C compilers behave identically regardless of the platform as ill-informed, narrow-minded and limiting. Yes, I appreciate "standards" and all that, but C has only recently, in terms of its lifetime (I have been pprogramming in C for over 30 years) been standardised, and its unreasonable to expect any embedded C to be fully standards compliant. By their very nature embedded processors, of which the PICs are a very limited example, require very close integration to the hardware and that requires, at the very least, extensions beyoond "standard". Its unrealistic to expect PIC C - any PIC C - to be portable and therefore for standards to be strictly adhered to.
It is the programmers job to get to know the tools they are using. Even simple things like the size of variables is not fully defined by standards, and therefore can and will vary between fully standards compliant Cs.
Personally I found CCS C's ints being unsigned unexpected. That they are 8 bit makes sense given the target processors. Case sensitivity has never bothered me as I learned to program on upper-case only terminals and therefore have always used unique names for all user-defined items (variables, types, functions, constants etc.) I understand and expect the limitations of constants. I don't expect to use dynamic memory - and never have in embedded code - and I use pointers very sparingly, and know that on some PICs memory segmentation causes trouble. I know that debuggers and IDEs have limited understanding of C types and therefore will often give me the wrong representation of variables. I know there is no stack and therefore I often can't watch local variables properly, particularly if I mix IDE, compiler and debugging hardware from different suppliers, such as MPLAB/CCS C.
There is much more. In short I know that I have to be on my toes. Should it be that way? No, in an ideal world it would not, but its not an ideal world. I live with that.
RF Developer |
|
![](templates/subSilver/images/spacer.gif) |
Ranfo
Joined: 08 Sep 2008 Posts: 38
|
|
Posted: Fri May 18, 2018 9:18 am |
|
|
I know the thread is old, but I just discovered an Overload issue causing a bug in my program. It seems the compiler could not differentiate between integer types and was using the DATE version regardless.
Code: |
// Add to Schedule DATE
// ----------------------------------------------------------------------------
void sch_addToSchedule(int32 pts, int8 index, int8 mnum) {
//...
}
// Add to Schedule DOW
// ----------------------------------------------------------------------------
void sch_addToSchedule(int8 dow, index, mnum) {
//...
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19364
|
|
Posted: Fri May 18, 2018 1:07 pm |
|
|
Depends obviously on how the 'dow' being passed is declared.
It works, but only really likes simply declared variables. So not pointers, and not items in a structure.
Also explicitly type all variables. You have two relying on the implicit 'int' declaration, but these will be different on different chips, and even if you use ANSI mode.... |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 18, 2018 3:24 pm |
|
|
It works with vs. 5.078. I ran the test program shown below in MPLAB
vs. 8.92 simulator and got the following output:
Quote: | 12345678, 55, aa
bb, cc, dd
|
Test program:
Code: |
#include <18F46K22.h>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOPBADEN
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
//------------------------------------------------------
// Add to Schedule DATE
void sch_addToSchedule(int32 pts, int8 index, int8 mnum)
{
int32 pts32;
int8 index8;
int8 mnum8;
pts32 = pts;
index8 = index;
mnum8 = mnum;
printf("%lx, %x, %x \n\r", pts32, index8, mnum8);
}
//-------------------------------------------
// Add to Schedule DOW
void sch_addToSchedule(int8 dow, index, mnum)
{
int8 dow8;
int8 index8;
int8 mnum8;
dow8 = dow;
index8 = index;
mnum8 = mnum;
printf("%x, %x, %x \n\r", dow8, index8, mnum8);
}
//======================================
void main()
{
sch_addToSchedule(0x12345678, 0x55, 0xAA);
sch_addToSchedule(0xBB, 0xCC, 0xDD);
while(TRUE);
} |
|
|
![](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
|