Live data from Hacker News

Basics Of Function Pointers In C

denniskubes.com

51–60 of 61 posts

Re: Basics Of Function Pointers In C

#51

Understanding function pointers in C unlocks the ability to write clean, object-oriented code with inheritance (kinda, sorta, shhhh). With great power, etc. etc.

> Understanding function pointers in C unlocks the ability to write clean, object-oriented code with inheritance (kinda, sorta, shhhh). People often say this in regards to pointers, or something similar like in the article too, "When understood, function pointers become a powerful tool in the C toolbox.", but often don't explain how/why. In the article the author says that at some indefinite point of time in future t…

>> "When understood, function pointers become a powerful tool in the C toolbox."

The callback pattern.

I have no idea if I just made that up or if it's a term in use, but it's where I most often find them useful. For instance the interface to libpcap. You can pass libpcap a function to call when it sees network traffic. Without this you would need some sort of polling in your own code. I've seen this in use in a variety of event-driven frameworks written in C.

The other major one I've implemented in the past is thread-pooling with job queues. You can make a queue of jobs that way. Each job is a struct containing a function pointer and a pointer to a struct of arguments. When a thread becomes idle it pulls the job off the queue and calls the function with the given args.

There are probably more. Yes you can kind-of mangle OO out of them, but I prefer the other uses.

Re: Basics Of Function Pointers In C

#52
post #22
post #7

But why that whole mess with function pointers? Where do they have the key advantage compared to directly calling the function?

Function pointers are useful anywhere you don't know what function you're going to call until runtime (and yet more useful still when the number of functions you could be calling is unlimited or extensible.) Sure, you can get away with, say, implementing a parser with a big switch statement that calls various parse_this() or parse_that() functions, depending on what kind of token you hit. On the other hand, you could…

This reminds me of how ECL (Embedded Common Lisp) loads lisp modules; it translates them to C, compiles them to PIC with a C compiler, and dynamically loads the resulting .o file.

Re: Basics Of Function Pointers In C

#54
Function pointers are a great tool for untangling balls of code and level-izing different components based upon dependencies in a large project. Rather than having to wait until all code is logically refactored, you can poke function pointers to higher-level functionality down into lower-level libraries to remove the physical link-time dependency and/or circular dependency loops.

There are other tricks you can use if your higher-level code is written in C++. You can take advantage of static initializers to do your function pointer poking for you instead of having to manually do it all in main() or some other point of initialization, potentially creating other physical dependencies. (As long as no other static initializers depend on the function pointers being in place, because order of execution is not guaranteed.) e.g.:

    extern "C" {
    static void higher_level_function_pointer(void) { ... }
    }

    namespace {
      class CallbackLoader {
        CallbackLoader() {
          lower_level_library_set_callback(&higher_level_function_pointer);
        }
      };
      static const CallbackLoader loader;
    }

Re: Basics Of Function Pointers In C

#55
post #4

Now it just needs the matching tutorial on initializing pointers in the data section :-)

Could you please elaborate?

Just the other day I was looking at some embedded SoC which had some data structures for setting up various GPIOs and pins and such, it was something like:

   struct gpio_config {
       uint8_t func;
       uint8_t options;
       uint32_t *loc;
   };

   struct gpio_alloc {
      struct gpio_config pins[4];
      struct gpio_alloc *next;
   };

   struct gpio_alloc fsmc_1 = {
              ...
   };
All the pre-initialization stuff (which was being stored in flash so it was really read-only data) was code I realized not a lot of people wrote in C these days.

Re: Basics Of Function Pointers In C

#57
post #48

Earlier quoted context omitted.

Let's look at the signature of qsort() from libc: void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); qsort is a function inside of libc.so. It's already been compiled. It doesn't know about the "compar" pointer you're going to pass it. That function might not even exist yet. qsort doesn't know if you're sorting integers, sorting strings, sorting struct foo which is still bei…

> qsort is a function inside of libc.so. It's already been compiled. Unfortunately, this is also why it is so damn slow. Try comparing C++ std::sort with C qsort, the performance gap is HUGE. The reason is that the "function pointer" std::sort gets inlined but qsort will actually invoke a function call via function pointer. If you'd move qsort to a header file as an inline function, the performance problem would go a…

This is one thing I don't understand about HN sometimes. I always get replies that seen to angrily "disagree". But I've already made your point in my parenthetical remark.

There are of course other times where the function pointer overhead doesn't matter as much and the modularity of not having things as templates is desirable. Sorting is just a bad example.

Re: Basics Of Function Pointers In C

#58
post #47

Earlier quoted context omitted.

Elaborating on the OO bit, as derefr did an excellent job of talking about the usefulness of function pointers in a VM. So, let's say I have a structure which I will use to represent objects in my game: typedef void (*thinkfunc_t)(void* self, unsigned int dt); typedef struct BaseFoo { float x,y,z; thinkfunc_t doThink; } BaseFoo; void null_think(void* self, unsigned int dt) { return 0; } /* empty think function */ Bas…

I don't see the need to do the "ret->doThink = null_think;" since you always pass ret to the function. Just call null_think( ret... )

Ah, but what if the object is handed over to some other deep end of the code? We want to bake the null behavior into it so that any Foo knows how to think itself--calling code just needs to be aware that any Foo object will always have a valid think callback defined.

This is basically the null-object pattern.

Re: Basics Of Function Pointers In C

#59
The C syntax really makes this simple feature look terribly complicated.

It's a while since I watched them, but in the SICP video lectures, as I recall, the notion of storing functions in variables - as introduced in, like, lecture 1 or 2 - took about 0.1% of the time - if indeed that. And that's because while the principles are actually more complicated than the C example (due to the lexically-scoped variable capture), the syntax is simplicity itself.

Consider the issue of making a variable, which goes something like this:

    (let ((x 1))
      (set! x (1+ x)))
You have your "let", then the list of names and values, and then the stuff that makes use of them.

Now consider the issue of making a function:

    (let ((x (lambda ()
               (message "stuff"))))
      (x))
(Well... maybe they called it define. I don't remember.)

The parallels are obvious, and indeed I suppose they deliberately chose this notation to emphasise the similarity between one type of value (e.g., an int) and any other (e.g., a closure). And so once you've got the hang of making a function that takes one type of value (e.g., an int), it's a small step from there to making a function that takes another type of value (e.g., a closure).

This is a dig at C and its ilk rather than the article. It's ridiculous that such a fundamental, basic primitive is given such a baroque syntax. But then C strikes me as designed for people who already know how to program so maybe the assumption is that most users will already know what function pointers are when they come to it, probably from being familiar with indirect jumps in assembly language.

This post is apropos of very little, I guess. I was just moved to comment after seeing six pages of stuff that still never got to the meat of the matter. So I suppose I should finish it like this: ""

Re: Basics Of Function Pointers In C

#60
Thanks for the link. I will pass this onto other developers I know who have trouble understanding this topic.

I recently read this book and it's the best book I've ever read about pointers in C:

Understanding and Using C Pointers Core techniques for memory management By Richard Reese Publisher: O'Reilly Media Released: May 2013 Pages: 226

http://shop.oreilly.com/product/0636920028000.do

Post reply on HN