Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Cromulent

macrumors 604
Original poster
Oct 2, 2006
6,812
1,100
The Land of Hope and Glory
I'm trying to fill in a few gaps in my knowledge of C and have started to look into function pointers. I understand how they work and what the process is but I can't for the life of me think of an example that I could play around with where they are really useful.

What is the main use of function pointers? The tutorial I have been reading is rather sparse on information (I mean it tells you how to use them and what the syntax is but it does not give me many ideas for simple programs I could write to get more comfortable with them).

Basically from what I have read they seem handy for replacing switch and if statements and for callbacks (something I also need to look into). I think I'm missing out on not understanding them as they seem a pretty important aspect of C.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
They are pretty rare in my experience. I maintain many thousands of lines of C at work, and there was one instance that used function pointers that was recently removed.

What I would CONSIDER using them for:

Faking structs to be more object like. If I have a few structs and each one needs to act differently (like polymorphism, etc.), there could be a "toString" function pointer that displays that struct in a particular way. You could have a list of functions that act on a node type in a node so they are handy, and the node could be used for different types of lists, etc. These are somewhat contrived.

Conditionally acting on something when the call needs to be made elsewhere. This is also rare, but may be needed for things like callbacks as you mentioned. Say I am checking a condition in function foo(). i know that based on this condition i may need to call barA() or barB() later, but not until I am in function foo2(). I could pass the function pointer to foo2() and it could use it. This is, again, somewhat contrived. You could just pass a "boolean" to foo2() and act based on that. When you get 10 cases it MIGHT be better to set a function pointer instead of passing a "key" and using a switch.

There are probably other (better) examples, but these were the cases I could think of.

-Lee
 

-Alan-

macrumors member
Mar 10, 2007
91
0
It's been ages since I programmed, but what comes to mind is passing the address of a function into a function.

Edit: I guess what I said doesn't communicate well. Suppose you don't know which function you need to pass into a function. That's where a pointer comes in handy.
 

yeroen

macrumors 6502a
Mar 8, 2007
944
2
Cambridge, MA
A good example of where function pointers are used are the Standard C Library sort functions: qsort, heapsort, and mergesort. These each take as an argument a pointer to a comparison function that you may define for your own types.

For example if you've defined a datatype, implemented as a struct, upon which some ordinal relation of "less than, greater than" holds, you'd define your own comparison function allowing you to determine which struct is "less than" another. You'd then pass a pointer to that function to the sorting routine so it knows how to perform comparisons of elements.

Function pointers are also how the C++ compiler implements virtual functions by creating a table (the vtable) of function pointers (and virtual functions are related to your remark about simplifying type-switching).

And of course, let's not forget event-driven GUI programming where you define callbacks for widgets.
 

Cromulent

macrumors 604
Original poster
Oct 2, 2006
6,812
1,100
The Land of Hope and Glory
Thanks for the tips.

Interesting that you mention things like pseudo object orientated uses for them.

Hmm, sounds interesting that you can do things like pass a function pointer to a function and then use the pointer to change what the function calls depending on the state of the function.

The question is though, how efficient are function pointers? I assume they are pretty fast as they are just the equivalent of the jump statement is assembly I assume?
 

Gelfin

macrumors 68020
Sep 18, 2001
2,165
5
Denver, CO
Quite fast, yeah. Somewhat faster than an Objective-C message send or C++ virtual function call.

Well, since a C++ vftable and an Objective-C class method table are, under the hood, pretty much just ways of managing collections of function pointers, you'd kind of expect this.

This tutorial page used to be at http://www.function-pointer.org, which I always thought was pretty cool. It's a decent site.

Most times you use a function pointer, it's to interface with somebody else's API. They'll give you a function prototype, you'll use it, and you'll hand off the name of your function as an argument. It's so simple you could do it without really even realizing you were using function pointers at all. It's when you have to implement the API yourself to support function pointers that you have to understand how it works.
 
You might also encounter function pointers through dynamic linking, e.g. accessing libraries through dlopen on UNIX or getProcAddress on Windows.

I think most of the uses have been addressed above but I would also add that it sometimes be more expressive or flexible to use function pointers. A simple example would be the use of transform in C++, which stores the return value from a function called on each item in one range into another (the benefits of this perhaps become more apparent if you have a complex series of loops for iteration, e.g. range within a multi-dimensional array, and want to call different functions on the items).

In addition to, or maybe rather than, thinking of function pointers as pseudo-OO, you might think of them as pseudo functional programming.
 

Sayer

macrumors 6502a
Jan 4, 2002
981
0
Austin, TX
I find it hard to believe you haven't used them yet. Although in Cocoa frameworks you use delegate methods and subclassing instead of function pointers. One are you may hit them is in the lower level of OS X like Core MIDI which isn't a Cocoa framework.

They typically have a defined type like a delegate method and are called from some other chunk of code - even other threads in the same app (Core MIDI)

No big deal.
 

pilotError

macrumors 68020
Apr 12, 2006
2,237
4
Long Island
In the old days...

I used them heavily when doing direct hardware writes to video cards. Different video cards had different addressing needs and after interrogating the hardware it would be assigned an appropriate set of functions, this way the higher level API's wouldn't need to know about what it was using.

I haven't used them since the days of writing DOS TSR's (Terminate Stay Resident) programs...

Edit: Actually, I do have call backs and pre/post processing of messages that use them. Duhhh. Never really thought much about it lately...
 

MrStevieP

macrumors newbie
Feb 27, 2008
22
0
State machine and call backs are the most common uses that I have come across. There is also quite alot of instances in Linux kernel/device driver development where they used extensively.

I think generally you wont use them in day to day C unless you want to do a state machine, hardware control or maybe graphics programming (Open GL uses them).

Whilst it has been mentioned that you can make C more C++ like using them, I wouldnt recommend it. If you are trying to impose object type behaviors, then it sounds like you really need objects proper and hence Objective-C or C++ or A.N other object derived language.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
<snip>
Whilst it has been mentioned that you can make C more C++ like using them, I wouldnt recommend it. If you are trying to impose object type behaviors, then it sounds like you really need objects proper and hence Objective-C or C++ or A.N other object derived language.

I was stretching on that example. The only time i'd consider carrying function pointers extensively with structs would be on a platform where an OO language is not an option. That's getting fewer and fewer, but sometimes C is all you have.

I don't think it's too far-fetched to pass a struct around that has a pointer to its comparator so it can easily be accessed for sorting or quick comparison to another struct of the same type.

-Lee
 

phjo

macrumors regular
Jan 8, 2008
149
1
Thanks for the tips.

Interesting that you mention things like pseudo object orientated uses for them.

Hmm, sounds interesting that you can do things like pass a function pointer to a function and then use the pointer to change what the function calls depending on the state of the function.

The question is though, how efficient are function pointers? I assume they are pretty fast as they are just the equivalent of the jump statement is assembly I assume?

I do use function pointers in my plotting framework... Just give the framework a pointer to a function you want to draw the graph, and let the framework do the work for you... Stupid example there :
http://www.mpkju.fr/~graphview/page1/page15/page15.html

In my experience, it is quite fast.

phjo
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
The speed of function pointers came up, and i thought i'd post an example. There is a trivial difference in calling a function via a pointer vs. a direct call. Here are two source programs:

testptr.c
Code:
#include <stdio.h>

void hello_world();
int main(int argc, char *argv[]) {
  void (*hello_call)() = NULL;
  hello_call = hello_world;
  hello_call();
  return 0;
}

void hello_world() {
  printf("Hello, World!\n");
}


testcall.c
Code:
#include <stdio.h>

void hello_world();
int main(int argc, char *argv[]) {
  hello_world();
  return 0;
}

void hello_world() {
  printf("Hello, World!\n");
}

I compiled both with gcc -S and got the following:
testptr.s:
Code:
        .file   "testptr.c"
        .def    ___main;        .scl    2;      .type   32;     .endef
        .text
.globl _main
        .def    _main;  .scl    2;      .type   32;     .endef
_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        movl    %eax, -8(%ebp)
        movl    -8(%ebp), %eax
        call    __alloca
        call    ___main
        movl    $0, -4(%ebp)
        movl    $_hello_world, -4(%ebp)
        movl    -4(%ebp), %eax
        call    *%eax
        movl    $0, %eax
        leave
        ret
        .section .rdata,"dr"
LC0:
        .ascii "Hello, World!\12\0"
        .text
.globl _hello_world
        .def    _hello_world;   .scl    2;      .type   32;     .endef
_hello_world:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        movl    $LC0, (%esp)
        call    _printf
        leave
        ret
        .def    _printf;        .scl    2;      .type   32;     .endef
        .def    _hello_world;   .scl    2;      .type   32;     .endef

testcall.s:

Code:
        .file   "testcall.c"
        .def    ___main;        .scl    2;      .type   32;     .endef
        .text
.globl _main
        .def    _main;  .scl    2;      .type   32;     .endef
_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        movl    %eax, -4(%ebp)
        movl    -4(%ebp), %eax
        call    __alloca
        call    ___main
        call    _hello_world
        movl    $0, %eax
        leave
        ret
        .section .rdata,"dr"
LC0:
        .ascii "Hello, World!\12\0"
        .text
.globl _hello_world
        .def    _hello_world;   .scl    2;      .type   32;     .endef
_hello_world:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        movl    $LC0, (%esp)
        call    _printf
        leave
        ret
        .def    _printf;        .scl    2;      .type   32;     .endef
        .def    _hello_world;   .scl    2;      .type   32;     .endef

The difference is pretty trivial:
diff testcall.s testptr.s
Code:
1c1
<       .file   "testcall.c"
---
>       .file   "testptr.c"
12,13c12,13
<       movl    %eax, -4(%ebp)
<       movl    -4(%ebp), %eax
---
>       movl    %eax, -8(%ebp)
>       movl    -8(%ebp), %eax
16c16,19
<       call    _hello_world
---
>       movl    $0, -4(%ebp)
>       movl    $_hello_world, -4(%ebp)
>       movl    -4(%ebp), %eax
>       call    *%eax

Only the last block of the diff represents the real difference.

These lines are setting up the pointer:
Code:
movl $0, -4(%ebp) //Initializes the function pointer to null
movl $_hello_world, -4(%ebp) //Sets function pointer to the address of the hello_world routine

These lines are actually making the call:
Code:
movl -4(%ebp), %eax //Move the function pointer into %eax to make the call
call *%eax //Call the code starting at the address in %eax

The assignment is done however many times you set up the pointer, but if you only set it once, the real difference is the complexity of the invocation. As you can see, that's only one movl, which is pretty trivial to execution time in my opinion.

-Lee
 

ChrisA

macrumors G5
Jan 5, 2006
12,917
2,169
Redondo Beach, California
I'm trying to fill in a few gaps in my knowledge of C and have started to look into function pointers. I understand how they work and what the process is but I can't for the life of me think of an example that I could play around with where they are really useful.

Think about operating systems, kernels, device drivers and real-time software and user configurable software

Any time you are implementing a plug-in system where user can add their own funtions your code will get a pointer to the user's function.

What about registering a "call back". In general this is a style of programing whare you assign functions to events and then you writte a loop which looks for events and then calls the corect function. Window systems work this way but the are many, many other real time programs that need to handle events (like if a robot arm hits a limit switch or a vision system "sees" something.)

I have an application I'm working on right now that reads in a set of specifications for a telemetry stream (from a rocket) and builds a program to process the telemetry. the program runs on a rather specialized custom computer. So my program is a kind of compilter. The "code generator" is table driven. when it sees a certain kind of data in the spec the table causes a function to be called to handle that kind of data. I could have used a switch but I wanted a table so I could use (say) binary search, switches are always linerar. Also the table remembers "state" (what do now depends on what was done on the last cycle) and there is more then one step where one table entry can point to another entry.

Function pointers in a table allow the logic to be changed at run-time via some kind of user interface wereas a big switch stament is configured at compile time. If the user is to be allowed to change the program's configuration. Or if it (as in my case) the program reads a "config file" at start up then the use of funtion pointers is required.
 

Cromulent

macrumors 604
Original poster
Oct 2, 2006
6,812
1,100
The Land of Hope and Glory
The speed of function pointers came up, and i thought i'd post an example. There is a trivial difference in calling a function via a pointer vs. a direct call. Here are two source programs:

<snip>

I would have thought the speed advantage would have been more noticable when calling functions recursively. I was under the impression that a function that takes arguments that are passed by value will copy the arguments into memory again where as a function pointer will point to the memory location of the already copied arguments etc. Am I wrong in that assumption?

Think about operating systems, kernels, device drivers and real-time software and user configurable software

Any time you are implementing a plug-in system where user can add their own funtions your code will get a pointer to the user's function.

What about registering a "call back". In general this is a style of programing whare you assign functions to events and then you writte a loop which looks for events and then calls the corect function. Window systems work this way but the are many, many other real time programs that need to handle events (like if a robot arm hits a limit switch or a vision system "sees" something.)

I have an application I'm working on right now that reads in a set of specifications for a telemetry stream (from a rocket) and builds a program to process the telemetry. the program runs on a rather specialized custom computer. So my program is a kind of compilter. The "code generator" is table driven. when it sees a certain kind of data in the spec the table causes a function to be called to handle that kind of data. I could have used a switch but I wanted a table so I could use (say) binary search, switches are always linerar. Also the table remembers "state" (what do now depends on what was done on the last cycle) and there is more then one step where one table entry can point to another entry.

Function pointers in a table allow the logic to be changed at run-time via some kind of user interface wereas a big switch stament is configured at compile time. If the user is to be allowed to change the program's configuration. Or if it (as in my case) the program reads a "config file" at start up then the use of funtion pointers is required.

Good points. Thanks for the help everyone.

So basically they allow C to become a more dynamic language meaning that you can delay certain program decisions until runtime when you have the data available?
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
I would have thought the speed advantage would have been more noticable when calling functions recursively. I was under the impression that a function that takes arguments that are passed by value will copy the arguments into memory again where as a function pointer will point to the memory location of the already copied arguments etc. Am I wrong in that assumption?
<snip>

Unless I have a fundamental misunderstanding (which is possible), making a direct function call vs. calling via a function pointer has no effect on the means by which parameters are passed. Passing a parameter via a pointer/reference instead of by value can make a difference for the reason you mentioned. If a pointer is smaller than your data type, at least. On x86-64 pointers are 48-bit, so char, int, float and their unsigned varieties are smaller than a pointer. Since the bus on that architecture is 64-bit, though, it's probably not a real difference for base types. When you have a large data structure that's when you will see a real difference.

-Lee

p.s. I think that the 48-bit pointer assertion was wrong. I think sizeof(void*) on x86-64 will be 8 bytes. I think one of the addressing modes is 48-bit, but that doesn't translate to how pointers are stored.
 

Sander

macrumors 6502a
Apr 24, 2008
521
67
A good example of where function pointers are used are the Standard C Library sort functions: qsort, heapsort, and mergesort. These each take as an argument a pointer to a comparison function that you may define for your own types.

Just a minor remark: heapsort and mergesort are not part of the Standard C Library.
 

yeroen

macrumors 6502a
Mar 8, 2007
944
2
Cambridge, MA
Just a minor remark: heapsort and mergesort are not part of the Standard C Library.

Well OK, "standard" as far as the implementation found on BSD/Darwin/OSX, but they are not universal. Headers for them may or may not be found in stdlib.h on Linux or Solaris.

BSD/Darwin/OSX also implements two versions of radix sort as part of the standard C library.
 

Sander

macrumors 6502a
Apr 24, 2008
521
67
Well OK, "standard" as far as the implementation found on BSD/Darwin/OSX, but they are not universal. Headers for them may or may not be found in stdlib.h on Linux or Solaris.

BSD/Darwin/OSX also implements two versions of radix sort as part of the standard C library.

It's probably glibc, right..? There are quite a few (nice) things in there which aren't part of C99 (or C89, for that matter).
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.