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 CCS Technical Support

Function pointer as a parameter
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hasanunal



Joined: 30 Jan 2019
Posts: 4

View user's profile Send private message

Function pointer as a parameter
PostPosted: Wed Jan 30, 2019 5:05 am     Reply with quote

Hi all,

First of all, I have a strong understanding on c#.

and a total newbie on C language.

The thing is, I want to write a function which accepts another function as a parameter.

I researched it but, haven't succeeded yet.

Code:

#include "main.h"
typedef void (*FUNC_PTR)();

void my_func()
{
// stuff to do
}
void wrapper(FUNC_PTR argument){
argument(); // ERROR: Expecting function name | ????
}
int main()
{
   
    wrapper(my_func);
   
    return 0;
}


I have found something similar to this. But doesn't work on my machine. Or IDE?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 30, 2019 5:24 am     Reply with quote

Are you using the CCS compiler ?
http://www.ccsinfo.com/m-compilers.php

The program below displays the following text in the Output window of
MPLAB vs. 8.92 when run in the MPLAB simulator:
Quote:
Hello World

Test program (compiled with PCH vs. 5.082):
Code:
#include <18F46K22.h>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOPBADEN
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

typedef void (*FUNC_PTR)();

void my_func()
{
printf("Hello World\n\r");
}

void wrapper(FUNC_PTR argument)
{
argument();
}

//======================================
void main()
{                                                                     

wrapper(my_func);

while(TRUE);
}
hasanunal



Joined: 30 Jan 2019
Posts: 4

View user's profile Send private message

PostPosted: Wed Jan 30, 2019 6:03 am     Reply with quote

I see.
I compiled them on CCS - PCW (v4.057).

Should it be a matter? I mean, this syntax is C right?

Why would I concern about IDE...
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 30, 2019 8:12 am     Reply with quote

The program doesn't compile with your old version from 2007.
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Wed Jan 30, 2019 9:48 am     Reply with quote

Straining back in the memory (that compiler must be about 8 years old...).
I think you had to explicitly use the standard C syntax to call the pointer
on these older versions. So in PCM_Programmers example, call as:

(*argument)();
hasanunal



Joined: 30 Jan 2019
Posts: 4

View user's profile Send private message

PostPosted: Thu Jan 31, 2019 2:38 am     Reply with quote

Ttelmah wrote:
Straining back in the memory (that compiler must be about 8 years old...).
I think you had to explicitly use the standard C syntax to call the pointer
on these older versions. So in PCM_Programmers example, call as:

(*argument)();


Many Thanks, It worked!

So, I should dig into standard C syntax for further learning.

Code looks like this now.
Code:

#include "main.h"
typedef void (*FUNC_PTR)();

void my_func()
{
   printf("¡Ay, caramba!");
}
void wrapper(FUNC_PTR argument)
{
   (*argument)(); // Calling a function pointer.
}
int main()
{
    wrapper(my_func);   
    return 0;
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Thu Jan 31, 2019 4:41 am     Reply with quote

Yes. 99% of CCS C, is directly K&R (Kernighan and Richie - the people who
originally developed C). The bracketed form shown, is how this type of
call is done in their original book. Now C has evolved, and CCS has moved
now to supporting a lot of the 'tweaked' forms in ANSI C99. Using the
pointer as PCM_Programmer shows, is one of those 'tweaks'.
Now CCS's following of the K&R 'bible', is for example illustrated strongly
in the numeric types. K&R, said that each compiler version should use as
it's native 'int', the default type supported by the processor. CCS followed this
directly, so the default 'int', (for PIC12, 16 & 18) is an unsigned int8. This
differs from most other C's, except many antique ones back when C was
first being developed, but is actually good for an embedded application
since it encourages efficient code.
Get a copy of "The C Programming language" by K&R. Preferably an early
edition, but even the modern 'ANSI' versions still show most of the older
syntax. You'll find that CCS will happily run most stuff in this.
However a separate comment. 4.057 is a very old compiler. It dates
before V4 was really well debugged (4.141, was a great V4 compiler and
works very well), and won't support a huge number of the more modern
chips.
hasanunal



Joined: 30 Jan 2019
Posts: 4

View user's profile Send private message

PostPosted: Thu Jan 31, 2019 6:50 am     Reply with quote

Ttelmah wrote:
Yes. 99% of CCS C, is directly K&R (Kernighan and Richie - the people who
originally developed C). The bracketed form shown, is how this type of
call is done in their original book..

Don't we have a THANK YOU button on this forum?
Thank you very much. I will get a newer version IDE for sure.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Sat Feb 02, 2019 6:43 pm     Reply with quote

I have never thought of doing this. Interesting.
Can someone elaborate on why or when this would be useful?

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Sun Feb 03, 2019 9:21 am     Reply with quote

Doing what?.
Reading the very original book that describes C?.
The point is that CCS C, is very much 'original C'. It has an option to make it
behave more like a relatively early ANSI C, but by default it keeps really
closely to the C language as originally described by K&R. As such the
primary 'reference' book should be their work, when using it....
jeremiah



Joined: 20 Jul 2010
Posts: 1354

View user's profile Send private message

PostPosted: Sun Feb 03, 2019 11:05 am     Reply with quote

Gabriel wrote:
I have never thought of doing this. Interesting.
Can someone elaborate on why or when this would be useful?

G.


This is essentially a precursor to what you see in many object oriented languages. Think baseclass => derived class patterns where you have a list of "automobiles" that you iterate through, but the specific types of automobiles may behave slightly differently.

One more practical example might be sensors. Say you have a collection of sensors on a board that you need to go through, run, get states from, and then process that new state data. You can generalize this into an "interface" of functions:

Code:

typedef struct{
    init_fn inititialize;
    poll_fn poll;
    proc_fn process;
    // some generic data members maybe...
} sensor_t;


you could then initialize one of these:
Code:

sensor_t temperature_sensor1 = {
   &temperature_sensor_initialize,
   &temperature_sensor_poll,
   &temperature_sensor_process
}

sensor_t current_sensor1 = {
   &current_sensor_initialize,
   &current_sensor_poll,
   &current_sensor_process
}

sensor_t sensors[10] = {
   temperature_sensor1,
   current_sensor1,
   // others
}



Then you could write your sensor handling code very generically:

Code:

//poll all sensors regardless of type.
for(i=0; i<NUM_SENSORS; i++){
   sensors[i].poll(/*whatever params you specified*/);
}


Same thing for communication systems. You can generalize basics and have different implementations but a generic "comms loop" or some such. It all depends on the system you have, the things you want to generalize, and your speed requirements (using function pointers in harvard architecture chips is more expensive than von neumann or modified harvard)

to your original question: To make this more "run time" selectable, you would skip out on the static initialization I showed above for a set of procedures that took a function pointer as a parameter and assigned that function to something (like the array I specified).

Quick example of idea:
Code:


volatile unsigned int g_sensor_count = 0;

BOOLEAN add_sensor(init_fn init, poll_fn poll, proc_fn proc) {
   if(g_sensor_count >= MAX_SENSORS){
      return FALSE:
   }
   sensors[g_sensor_count].initialize = init;
   sensors[g_sensor_count].poll = poll;
   sensors[g_sensor_count].process = proc;
   g_sensor_count++;
   return TRUE;
}


You can get as fancy as you like (adding/removing sensors based on some runtime event, etc.).

Basically, this is what is called "using callbacks" to generalize your code as you were storing a "call" to be used later.

The benefit to this is when you make changes later. If you need to add or remove a sensor later, then you need to modify and maintain less specific code and that code is usually contained to much smaller areas (even up to a single function or files in some cases). But it can take a lot of design choices to get there. Frameworks can also make good prisons, so there are tradeoffs.
allenhuffman



Joined: 17 Jun 2019
Posts: 554
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

Passing address of function (function pointer)as a parameter
PostPosted: Mon Jun 24, 2019 9:25 am     Reply with quote

Thanks for posting this.

I learned C in the late 1980s on a K&R K&C C compiler, but I never made use of function pointers until much later.

I am porting some working code I wrote in GCC over to CCS, and trying to get something very basic to work.

Since the "modern" C version of passing a function pointer in as a parameter didn't work, I was trying to bypass that and use void pointers. Here is a very simple example of what I was trying to do:

Code:
#include <FunctionPtr.h>

int (*functionPtr)(int x, int y);

int add( int x, int y )
{
   return (x + y);
}

int sub( int x, int y )
{
   return (x - y);
}

void setFunctionPtr( void *ptr )
{
   functionPtr = ptr;
}

void main()
{
   int result = 0;

   functionPtr = &add;
   setFunctionPtr( functionPtr );
   result = (*functionPtr)( 1, 2 );

   functionPtr = &sub;
   setFunctionPtr( functionPtr );
   result = (*functionPtr)( 5, 1 );

   while(true)
   {
   }
}


While the note about using "(*functionPtr)( 1, 2)" solved one issue, I am still trying to re-learn how to pass a function pointer as a parameter. To get my code working, I ended up just assigning a pointer and passing that in:

Code:
   functionPtr = &sub;
   setFunctionPtr( functionPtr );


…but ideally, I'd just want to pass the function address in directly. As I mentioned, I have it working (a much more complex thing than this trivial example) on GCC, but do not yet know how to get it working on CCS.

Any tips on how to make something like this work?

Code:
   setFunctionPtr( &add );


Thanks!
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 24, 2019 10:20 am     Reply with quote

Post a full test program so we don't have to make one.

Post the contents of the FunctionPtr.h file.

Post your compiler version.

Post your PIC, if not specified in FunctionPtr.h.
allenhuffman



Joined: 17 Jun 2019
Posts: 554
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Jun 25, 2019 9:42 am     Reply with quote

PCM programmer wrote:
Post a full test program so we don't have to make one.

Post the contents of the FunctionPtr.h file.

Post your compiler version.

Post your PIC, if not specified in FunctionPtr.h.


Thanks!

That is my full test program Smile The FunctionPtr.h is whatever the PIC24 wizard made, though on our custom hardware I modify the delay values.

Code:
#include <24FJ256GA106.h>
#device ICSP=1
//#use delay(crystal=20000000)
#use delay(crystal=8MHZ, clock=32MHZ)

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES CKSFSM                   //Clock Switching is enabled, fail Safe clock monitor is enabled


I have several PIC24 variations I work with. This is just a general language question, not an IDE or processor specific question.

I have my code working just fine, but I would be curious to know if there is a way to do it "better" with this compiler.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

Re: Passing address of function (function pointer)as a param
PostPosted: Wed Jun 26, 2019 2:33 pm     Reply with quote

allenhuffman wrote:

…but ideally, I'd just want to pass the function address in directly.
Any tips on how to make something like this work?

setFunctionPtr( &add );

I was able to make it work by casting the function pointer address
to an int16 in three places. I tested this with CCS vs. 5.085.
The program shown below displays the following result in the MPLAB
vs. 8.92 simulator output window:
Quote:
add: 3
sub: 4

Test program:
Code:

#include <18F46K22.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

int (*functionPtr)(int x, int y);

//-------------------------------
int add( int x, int y )
{
return (x + y);
}

//-------------------------------
int sub( int x, int y )
{
return (x - y);
}
//-------------------------------

void setFunctionPtr(int16 ptr)
{
functionPtr = ptr;
}

//=================================
void main()
{
int result = 0;

setFunctionPtr((int16)&add);
result = (*functionPtr)( 1, 2 );
printf("add: %d\r", result);


setFunctionPtr((int16)&sub);
result = (*functionPtr)( 5, 1 );
printf("sub: %d\r", result);
 
while(TRUE);
}



But you can avoid the castings to int16 if you skip your setFunctionPtr()
function and just set functionPtr to the routine address with a line of
code. You don't need &sub and &add. Just using 'sub' and 'add' will work.
It produces the same code in the .LST file.
See the changes in main() below:
Code:
#include <18F46K22.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

int (*functionPtr)(int x, int y);

//-------------------------------
int add( int x, int y )
{
return (x + y);
}

//-------------------------------
int sub( int x, int y )
{
return (x - y);
}

//=================================
void main()
{
int result = 0;

functionPtr = add;
result = (*functionPtr)( 1, 2 );
printf("add: %d\r", result);


functionPtr = sub;
result = (*functionPtr)( 5, 1 );
printf("sub: %d\r", result);
 
while(TRUE);
}
 
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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