Benjamin Barrois
Benjamin Barrois

Reputation: 2686

Function pointers in C - nature and usage

I have just read an interesting question here that makes me wonder about two more things:

  1. Why should anyone compare function pointers, given that by conception, functions uniqueness is ensured by their different names?
  2. Does the compiler see function pointers as special pointers? I mean does it see them like, let's say, pointers to void * or does it hold richer information (like return type, number of arguments and arguments types?)

Upvotes: 32

Views: 6233

Answers (7)

Ajay Brahmakshatriya
Ajay Brahmakshatriya

Reputation: 9203

  1. Why would someone compare pointers? Consider the following scenario -

    You have an array of function pointers, say it is a call back chain and you need to call each one of them. The list is terminated with a NULL (or sentinel) function pointer. You need to compare if you have reached the end of the list by comparing with this sentinel pointer. Also, this case justifies previous OPs concern that different functions should have different pointers even if they are similar.

  2. Does the compiler see them differently? Yes. The type information includes all the information about the arguments and the return type.

    For example, the following code will/should be rejected by the compiler -

    void foo(int a);
    void (*bar)(long) = foo; // Without an explicit cast
    

Upvotes: 19

Serge Ballesta
Serge Ballesta

Reputation: 148880

The classical part about function pointers is already discussed in other's answer:

  • Like other pointers, pointers to function can point to different objects at different time so comparing them can make sense.
  • Pointers to function are special and should not be stored in other pointer types (not even void * and even in C language).
  • The rich part (function signature) is stored in the function type - the reason for the above sentence.

But C has a (legacy) function declaration mode. In addition to the full prototype mode that declares the return type and the type for all parameters, C can use the so called parameter list mode which is the old K&R mode. In this mode, the declaration only declares the return type:

int (*fptr)();

In C it declares a pointer to function returning an int and accepting arbitrary parameters. Simply it will be undefined behaviour (UB) to use it with a wrong parameter list.

So this is legal C code:

#include <stdio.h>
#include <string.h>

int add2(int a, int b) {
    return a + b;
}
int add3(int a, int b, int c) {
    return a + b + c;
}

int(*fptr)();
int main() {
    fptr = add2;
    printf("%d\n", fptr(1, 2));
    fptr = add3;
    printf("%d\n", fptr(1, 2, 3));
    /* fprintf("%d\n", fptr(1, 2)); Would be UB */
    return 0;
}

Don't pretend I have advised you to do so! It is now considered as an obsolescent feature and should be avoided. I am just warning you against it. IMHO it could only have some exceptional acceptable use cases.

Upvotes: 5

R Sahu
R Sahu

Reputation: 206567

  1. Why should anyone compare function pointers, given that by conception, functions uniqueness is ensured by their different names?

A function pointer can point to different functions at different times in a program.

If you have a variable such as

void (*fptr)(int);

it can point to any function that accepts an int as input and returns void.

Let's say you have:

void function1(int)
{
}

void function2(int)
{
}

You can use:

fptr = function1;
foo(fptr);

or:

fptr = function2;
foo(fptr);

You might want to do different things in foo depending on whether fptr points to one function or another. Hence, the need for:

if ( fptr == function1 )
{
    // Do stuff 1
}
else
{
    // Do stuff 2
}
  1. Does the compiler see function pointers as special pointers? I mean does it see them like, let's say, pointers to void * or does it hold richer information (like return type, number of arguments and arguments types?)

Yes, function pointers are special pointers, different from pointers that point to objects.

The type of a function pointer has all that information at compile time. Hence, give a function pointer, the compiler will have all that information - the return type, the number of arguments and their types.

Upvotes: 18

Lundin
Lundin

Reputation: 213523

1) There are lots of situations. Take for example the typical implementation of a finite state machine:

typedef void state_func_t (void);

const state_func_t* STATE_MACHINE[] =
{
  state_init,
  state_something,
  state_something_else
};

...

for(;;)
{
  STATE_MACHINE[state]();
}

You might need to include some extra code in the caller for a specific situation:

if(STATE_MACHINE[state] == state_something)
{
  print_debug_stuff();
}

2) Yes the C compiler sees them as distinct types. In fact function pointers have stricter type safety than other types of C, because they cannot get implicitly converted to/from void*, like pointers to object types can. (C11 6.3.2.3/1). Nor can they be explicitly cast to/from void* - doing so would invoke non-standard extensions.

Everything in the function pointer matters to determine its type: the type of the return value, the type of the parameters and the number of parameters. All of these must match, or two function pointers are not compatible.

Upvotes: 2

Dmitry Grigoryev
Dmitry Grigoryev

Reputation: 3204

Function pointers are variables. Why should anyone compare variables, given that by concept, variables uniqueness is ensured by their different names? Well, sometimes two variables can have the same value and you want to find out whether it's the case.

C considers pointers to functions with the same argument list and return value to be of the same type.

Upvotes: 1

Why should anyone compare function pointers? Here's one example:

#include <stdbool.h>

/*
 * Register a function to be executed on event. A function may only be registered once.
 * Input:
 *   arg - function pointer
 * Returns:
 *   true on successful registration, false if the function is already registered.
 */
bool register_function_for_event(void (*arg)(void));

/*
 * Un-register a function previously registered for execution on event.
 * Input:
 *   arg - function pointer
 * Returns:
 *   true on successful un-registration, false if the function was not registered.
 */
bool unregister_function_for_event(void (*arg)(void));

The body of register_function_for_event only sees arg. It doesn't see any function name. It must compare function pointers to report someone is registering the same function twice.

And if you want to support something like unregister_function_for_event to complement the above, the only information you have is the function address. So you again would need to pass it in, and compare against it, to allow removal.

As for the richer information, yes. When the function type contains a prototype, it's part of the static type information. Mind you that in C a function pointer can be declared without a prototype, but that is an obsolescent feature.

Upvotes: 36

user541686
user541686

Reputation: 210402

Imagine how you would implement functionality similar to that of WNDCLASS?

It has a lpszClassName to distinguish window classes from each other, but let's say you didn't need (or didn't have) a string available to distinguish different classes from each other.

What you do have is the window class procedure lpfnWndProc (of type WindowProc).

So now what would you do if someone calls RegisterClass twice with the same lpfnWndProc?
You need to detect re-registrations of the same class somehow and return an error.

That's one case when the logical thing to do is to compare the callback functions.

Upvotes: 2

Related Questions