

A Simply Neat Example of Function Pointers in C - ilovecomputers
http://stoneship.org/journal/2007/a-c-function-pointer-example/

======
alexgartrell
Example of function pointers in the linux kernel:
<http://lxr.linux.no/linux+v2.6.32/include/net/sock.h#L297>

The cool thing about this is that, if you want to make your kernel socket
'event-driven', you can actually use this method to overwrite them and
'hijack' the callback. Then, when you're doing doing what you wanted to do,
you can punt to the original callback (which you, hopefully, saved)

Example of this taking place:
[http://lxr.linux.no/linux+v2.6.32/drivers/scsi/iscsi_tcp.c#L...](http://lxr.linux.no/linux+v2.6.32/drivers/scsi/iscsi_tcp.c#L195)

------
chipsy
Function pointers are a good means of allowing "flexible" finite state
patterns, by making each function a state, directing all program flow to a
"next" function pointer, and using conditionals within each state to begin
transitions:

    
    
      /* an "active" state where a timer decrements unless the user hits a key. */
      if (timer<1) {prep_for_idle(); next = idle;}
      else if (user_hit_key) {timer+=100; next = active;}
      else {timer--; next = active;}
    

I use this pattern in haXe and Python, not C, but it applies equally well.

~~~
mahmud
What do you compile your haXe to?

~~~
chipsy
Flash 10, mostly. Sometimes Neko.

~~~
mahmud
What is neko used for mostly?

------
dlsspy
That's a pretty design, but a rather typical function pointer demonstration.
It's at least more unusual if you change main to this:

    
    
        int main(void) {
            char *sayings[] = {
                "I know a secret!", "WHAT", "WHAT again", NULL
            };
            int i = 0;
        
            for (i = 0; sayings[i]; i++) {
                (i ? say_loud : say_soft)(sayings[i]);
            }
        	return 0;
        }

------
jrockway
I modified the program so that the main function looks like:

    
    
      say = NULL;
      say("OH NOES");
    

When compiled with all warnings on, there are none. When run, it immediately
segfaults. (The same would happen with any assignment from void*, like 'say =
malloc(42)'. Nice.)

Edit: I knew this would get downmodded :) Why does any post implying that type
safety is good get downmodded?

~~~
nitrogen
Maybe because people know by now that C doesn't hold your hand :). The
compiler did exactly what you told it to do. And, in fact, since C is
frequently used for writing operating system code, what you wrote may actually
be a valid operation if the OS maps critical functions into page 0 (which I
believe some older systems did).

~~~
jrockway
_what you wrote may actually be a valid operation if the OS maps critical
functions into page 0_

Then you'd better not call it NULL. "0 and NULL are the same" was how I first
got root on my phone ;)

~~~
coliveira
In C++ 0 and NULL are the same by definition. Just look at Stroustrup's C++
Style and Technique FAQ.

~~~
Imprecate
Assigning the value 0 or NULL to a pointer does not necessarily set it to
address 0.

------
Maro
Real world usage: an event-based architecture like the one employed in
Keyspace [1]. We have an abstract class Callable, which has a member virtual
void Execute() and a global convenience function Call(Callable) which just
calls ->Execute(). So a Callable is something that can be called, ie. a
function pointer. We then have two concrete implementations, one for global
(C) function pointers and one for class member (C++) function pointers. The
whole thing is in Callable.h and is <100 lines of code, hence very
lightweight.

Then, in the framework layer, we register callbacks using Callables in the
IOProcessor. So if you create a TCP server with a TCP listening socket, you
have a TCPRead object and you set its onComplete member, which is a Callable,
to &TCPServer::OnConnect and analogously for onClose. Then, once a connection
is establised you post TCPRead or TCPWrite objects for the new socket to
IOProcessor to receive read notifications or perform writes, again with
members onComplete and onClose.

Then, in the application layer you have actual database code which uses the
network abstractions in the framework layer (which abstract away I/O), but
they also use Callables to have themselves get called back when, for example
an entire message has been read (eg. command is then parsed and executed) from
the TCP stream or a client connection is terminated (eg. commands are
canceled).

The whole program is then one big infinite loop, each iteration
IOProcessor::Poll() being waken up by the O/S because something has happened,
and Callables being called in turn. (On BSD, we kqueue, on Linux epoll and on
Win32 Completion Ports to receive readyness notifications.) We also have
support timers, which are just a linked list of Callables, and when
IOProcessor::Poll() blocks we pass in the amount of time until the next timer
must be executed as the timeout.

Or you can use libev/libevent, but they're not lightweight and will force you
to do things their way.

[1] AGPL source is at <http://scalien.com>

------
rayval
A common use of function pointers is in a dispatch table. For example, in a
text editor, every ASCII character value, including control-characters and
printable characters, is used as an index into an array of function pointers,
each one of whom represents a function. For example the ^N character retrieves
a function pointer for the moveToNextLine() function. The printable characters
all are insertSelf() function.

Use of typedefs make the code more readable.

Instead of: int (* var_pointer_to_function)(int)

one must first do: typedef int (* funcptr)(int)

which is initially equally messy, but then allows one to declare function
pointer variables in a simple succinct manner: funcptr foo

------
alttab
More importantly, function pointers can be used (especially in type
definitions) as a way for polymorphism and object oriented code in C.

If you have a struct, and it has type definition pointers in it, you can
create a set of initialization functions that set the function pointers to the
correct "class functions" of that type.

I use function pointers in C everyday and it makes coding more robust and
extremely easy to get the performance out of OOP code in a procedural
environment when C++ isn't an option.

~~~
cperciva
I think it's safe to say that most uses of function pointers in C fall into
one of two categories: 1. Objects; 2. Continuations; 3. Callbacks from generic
algorithms.

A classic example of the first category is in the VFS layer of BSD UNIX:
Filesystems provide a standard set of functions for
open/read/write/ioctl/stat/close/etc, which all sit in a structure, and the
upper layers of the kernel generally invoke those functions without knowing
which underlying filesystem is handling them.

A classic example of the second category is event-driven loops: You register
"when there's data on socket N, please call this function with this cookie",
and the event loop doesn't need to know what the function does or what sort of
data you have stored in the cookie. In this way, you can have several
different things going on, passing control back and forth by registering "what
happens next" and returning.

A classic example of the third category is qsort: There is no requirement for
qsort to know what sort of data it is quicksorting, since it invokes the
provided callback function whenever it needs to compare two values.

~~~
pgbovine
isn't your event-driven loop an example of a callback function? i'm no expert
on continuations, but i thought they involved somehow packaging up the 'rest
of the computation' in some structure and then running it. your example seems
to be an ordinary callback.

~~~
zb
He did say there were only two categories. They're just numbered 1 through 3
for some reason ;-)

------
jacquesm
Another favorite is simple embedded languages where every statement or
function has an entry in a table with a pointer to the function for execution.

That makes for a very simple parser.

------
danblick
The same site has an interesting example of reference counting:

[http://stoneship.org/journal/2007/c-reference-counting-
and-y...](http://stoneship.org/journal/2007/c-reference-counting-and-you/)

------
ticktock
welcome to 1988

------
ighost
I'd like to congratulate you on your C function pointer hello world.

Not how he avoided using & or deref in the first snippet.

