Defining function pointer in C?

133 Views Asked by At
  1. Recently I came across a surprising way of defining a function pointer in C:
typedef void (func_type)(void);
func_type *func_ptr;

Is this a correct way of defining a function pointer?

  1. If we define func_obj as below, what is the type of this object and what this object can be used for?
#include <stdio.h>

typedef void (func_type)(void);
func_type *func_ptr;

func_type func_obj;

int main()
{
  printf("Size of func_obj: %zu\n", sizeof func_obj);
  printf("Size of func_ptr: %zu\n", sizeof func_ptr);
  return 0;
}

The code prints:

Size of func_obj: 1
Size of func_ptr: 8
3

There are 3 best solutions below

4
Vlad from Moscow On BEST ANSWER

These declarations

typedef void (func_type)(void);
func_type *func_ptr;

are similar to declarations like for example

typedef int T;
T *int_ptr; 

So there is nothing wrong with the typedef that intrduces an alias for a function type.

Pay attention to that this typedef declaration

typedef void (func_type)(void);

is equivalent to

typedef void func_type(void);

This declaration

func_type func_obj;

declares a function with the name func_obj of the type void( void ).

Such a declaration allows for example to list functions in one line without repeating their parameter lists.

This statement

printf("Size of func_obj: %zu\n", sizeof func_obj);

is invalid according to the C Standard because you may not apply the sizeof operator to a functon.

From the C Standard (6.5.3.4 The sizeof and alignof operators)

1 The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member. The alignof operator shall not be applied to a function type or an incomplete type.

Some compilers however can have their own extensions that contradict the C Standard.

0
KamilCuk On

s this a correct way of defining a function pointer?

Yes.

I prefer to define a function type and then use * with it. It is immediately visible that func_type * is a pointer, vs typedef void (*func_type)(void); func_type func; hides that information.

func_obj as below, what type if this object of?

func_obj is literally a function. Consider:

#include <stdio.h>
typedef void func_type(void);
// forward declaration of a function
void func_obj(void);
// typedef is just an alias, exactly the same as above
func_type func_obj;
// for function definition, we have to use a ()
void func_obj(void) {
    printf("Inside func_obj\n");
}
int main() {
     func_obj();
}

Doing sizeof(func_obj) is technically invalid - What does 'sizeof (function name)' return? .

what this object can be used for?

Well, like a function, for calling it. Alias can be used for keeping function types in sync.

2
Lundin On

Is this a correct way of defining a function pointer?

Yes. There are two different coding styles:

  • Either typedef a function and declare an object as a pointer to that function:;

    typedef void func_t (void);
    ...
    func_t* fptr;
    
  • Or hide the pointer inside the typedef:

    typedef void (*func_t) (void);
    ...
    func_t fptr;
    

Which one to use is mostly a matter of preference.

The former makes function pointers behave as object pointers do, so it is nice for consistency and what I would personally recommend. It is generally a bad idea to hide pointers inside a typedef. Good code should be self-documenting.

The latter is historically the most common and you are expected to understand it as well. I used it too for a long while before I converted to the former style.


If we define func_obj as below, what is the type of this object and what this object can be used for?

It declares a function type. It is another dangerous GNU C thing - you cannot apply sizeof on a function in conforming C (see constraints 6.5.3.4). gcc and clang are clearly non-conforming here unless you add -pedantic.

As for what the purpose of this "feature" is... as with any other such mildly useful GNU C feature: implemented for the sake of implementing new features. I can't find any rationale or explanation anywhere for what this "feature" would actually be good for. What it is bad for is quite obvious: it reduces type safety of the sizeof operator.