Delegates vs. Function Pointers, part 2: C

This is part 2 in a series about state and function pointers; part 1 is here.

Unlike most other languages, it is not possible to include any form of state in a function pointer in C.  Therefore, it is impossible to fully implement closures in C without the cooperation of the call-site and/or the compiler.

To illustrate what this means in practice, I will refer to my standard example, using a filter function to find all elements in an array that are greater than x.  Since C doesn’t have any such function, I’ll write one myself, inspired by qsort:

void* filter(void* base, 
             size_t count, 
             size_t elemSize, 
             int (*predicate)(const void *)) {
    //Magic...
}

With this function, one can easily find all elements that are greater than some constant:

int predicate(const void* item) {
        return *(int*)item > 2;
}

int arr[] = { 1, 2, 3, 4 };
filter(arr, 4, sizeof(int), &predicate);

However, if we want to replace the hard-coded 2 with a local variable, it becomes more complicated.  Since function pointers, unlike delegates, do not have state, there is no simple way to pass the local variable to the function.

The most obvious answer is to use a global variable:

static int minimum;
int predicate(const void* item) {
        return *(int*)item > minimum;
}

int arr[] = { 1, 2, 3, 4 };
minimum = x;
filter(arr, 4, sizeof(int), &predicate);

However, this code will fail horribly if it’s ever run on multiple threads.  In simple cases, you can work around that by storing the value in a global thread-local variable (or in fiber-local storage for code that uses fibers).   Because each thread will have its own global, the threads won’t conflict with each-other.  Obviously, this won’t work if the callback might be run on a different thread.

However, even if everything is running on one thread, this still isn’t enough if the code can be re-entrant, or if the callback might be called after the original function call finishes.  This technique assumes that exactly one callback (from a single call to the function that accepted the callback) will be used at any given time.  If the callback might be invoked later (eg, a timer, or a UI handler), this method will break down, since all of the callbacks will share the same global.

In these more complicated cases, one can only pass any state with the cooperation of the original function.  In this (overly simple) example, the filter method can be modified to take a context parameter and pass it to the predicate:

void* filter(void* base, 
             size_t count,
             size_t elemSize, 
             int (*predicate)(const void *, const void *), 
             const void* context) {
        //More magic...
}
int predicate(const void* item, const void* context) {
        return *(int*)item > *(int*)context;
}

int arr[] = { 1, 2, 3, 4 };
filter(arr, 4, sizeof(int), &predicate, &x);

To pass around more complicated state, one could pass a pointer to a struct as the context.

Next Time: C# 1.0

19 comments:

Ahh this brings back memories of the pain of using function pointers with C++, the crazy syntax and workarounds, http://www.newty.de/fpt/callback.html#

I love how C# and .NET makes all this so much easier.

Nice series BTW, cheers

@Matt: With functors, it is now much easier to do this in C++ (not to mention C++0x, which supports closures). Wait for part 5.

The above article is nice and interesting, thank you willing to share! Greetings success of admin Percetakan Murah Rawamangun Jakarta Timur wish you deign to visit my website, thank you :)

I advise you to learn how to brainstorm good college essay topics. It will help you to achieve success in college

Hello, thanks for sharing this interesting information. The material which is mentioned here helps me a lot while I work on my marrakech by george orwell summary task.

Hello there. it's a good item for me. moreover, reading blogs helps me to improve my skills. It's important for my job because I'm a writer at https://300writers.com/case-brief.html

This is a very interesting article for a student who studies information technology at the University. By the way, I write problem solution speech about this.

This comment has been removed by the author.

The c programming language is a simplicity, portability and efficiency. The C++ is a object oriented programming language. The information about the c language is very useful and creative. Using of delegates and the function pointers are explained very well. Traffic Lawyer Petersburg VA

Uncontested divorce process in virginia
Streamline your divorce with our Virginia uncontested divorce process. Our experienced team guides you through the efficient and amicable resolution, minimizing stress and ensuring a smooth legal separation.

New York State Divorce Forms New York State provides various divorce forms, including those for uncontested and contested divorces, available through the court system's website or from legal assistance resources.

Delegates and function pointers are both mechanisms for referencing methods or functions, but they have distinct differences, especially in the context of their usage in programming languages like C# and C/C++ bk lawyer near me

"Delegates" explores the role and responsibilities of representatives in various organizational and governmental contexts. It highlights how delegates influence decision-making and advocate for their constituents' interests. The discussion provides insights into the dynamics of representation and the impact of effective delegation on policy and leadership. An informative read for understanding the importance of delegate roles in governance and management.
divorce laws in virginia

Delegates and function pointers are two key concepts in C# and C programming. Delegates can encapsulate a method's state, allowing it to carry a reference to the object it is associated with. They can be multicast, allowing a single delegate to invoke multiple methods in sequence. Delegates are type-safe, checking method signatures at compile time to avoid runtime errors How Many Points is Careless Driving in New Jersey.


Part 2 of "Delegates vs. Function Pointers" dives into the differences and applications of delegates and function pointers specifically in the C programming language. It explores how function pointers are used to achieve similar behavior to delegates, enabling flexible function calling and callback mechanisms. This blog post is ideal for programmers looking to deepen their understanding of functional programming concepts in C.Traffic Lawyer Bland VAA lawyer, an advocate of justice, navigates the complex legal landscape with expertise and diligence.

Post a Comment