3

I would like to know if it is possible to define a function type using typedef, I tried this syntax:

typedef int (*) (void *, void *) order;

But it doesn't work. Error message : expected identifier or '(' before ')' token

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
ThunderPhoenix
  • 1,649
  • 4
  • 20
  • 47
  • Possible duplicate of [Understanding typedefs for function pointers in C](https://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c) – mkrieger1 Nov 25 '19 at 11:03

4 Answers4

13

The alias name should be placed where a variable name would be if it was a variable declaration.

Here:

typedef int (*order) (void *, void *);
//            ^~~~~

Or, if you want a function type rather than a pointer-to-function:

typedef int order(void *, void *);
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • What is the reason behind declaring a function type? – ThunderPhoenix Nov 25 '19 at 12:11
  • @ThunderPheonix It's not very useful. You could use it to declare functions: `order foo; -> int foo(void*, void*);`. Or, if you add a star, function pointers: `order *ptr;` (the pointer-to-function typedef does the same thing without the star). – HolyBlackCat Nov 25 '19 at 13:18
  • Actually I need a pointer to a function in order to do a cast when calling `qsort` function. – ThunderPhoenix Nov 25 '19 at 13:22
  • @ThunderPheonix I thought you were asking about functions vs pointers-to-functions. In any case, casting a function to a function pointer that has different parameter types or return type is a bad idea, and calling the resulting pointer causes undefined behavior (see [C11 6.3.2.3/8](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)). – HolyBlackCat Nov 25 '19 at 13:37
  • I just wanted to avoid the warning message of `qsort`! – ThunderPhoenix Nov 25 '19 at 14:07
  • @ThunderPheonix Make sure the function you pass to it looks like `int name(const void *, const void *)`. Then you wouldn't need a cast. – HolyBlackCat Nov 25 '19 at 14:12
  • Actually my function takes two struct element as parameter and compare them according to struct members. So it looks like `int comp (const struct element *, const struct element *)`. And it worked well. I don't understand why it is a bad idea to do a cast? – ThunderPhoenix Nov 25 '19 at 19:41
6

This typedef

typedef int (*order )(void *, void *);

defines an alias for the type of pointer to function of the type int( void *, void * ).

This typedef

typedef int order(void *, void *);

defines an alias for the type of function of the type int( void *, void * ).

If to use one typedef to define both the alias for pointer and the alias for function you can write

typedef int ( *porder )( void *, void * ), order(void *, void *);

or even the following way

int typedef ( *porder )( void *, void * ), order(void *, void *);

Pay attention to that you can use either typedef name as a type specifier for a function parameter. For example these two declarations

void h( porder arg );
void h( order arg );

declare the same one function because the compiler adjusts implicitly the type of a parameter having a function type to pointer to the function type.

However you may not use interchangeably these typedef(s) for the function return type because functions may not return functions but they may return pointers to functions. So this declaration

porder h( void );

will compile. But this declaration

order h( void );

will not compile.

Without the typedef the declaration of a function that returns pointer to other function would be complicated. For example this declaration

porder h( void );

without the typedef looks like

int ( *h( void ) )( void *, void * );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • @Lundin I showed this example because in the answer of glglgl there was shown an invalid construction of a typedef for both declarators. – Vlad from Moscow Nov 25 '19 at 11:38
  • Still you would never write them on the same line. – Lundin Nov 25 '19 at 11:39
  • @Lundin Be calm. Syntax training exercises are very important to better understand language constructs – Vlad from Moscow Nov 25 '19 at 11:43
  • Not if you don't point out that a certain syntax is bad practice. Before you know it, you'll have newbies writing code like `int* x, (*y)(int), z;`. – Lundin Nov 25 '19 at 11:47
  • Yeah so if even a veteran programmer can't get it right, it says something about how bad and infrequently used that syntax is... – Lundin Nov 25 '19 at 11:55
  • your last example is useful ... I found some declarations of function returning pointer to function in OpenSSL that I simply could not understand – zentrunix Jan 18 '22 at 11:22
2

You do either of

typedef int (*order) (void *, void *);
typedef int order(void *, void *);

depending on if you want to typedef the function or the pointer.

Both has advantages and disadvantages; I prefer a style where a pointer is visible as such and have my functions defined as

order order_impl;
int order_impl(void * a, void * b)
{
}
order * order_pointer = order_impl;

This ensures that the function is defined properly.

Others, however, prefer working with the function pointer type and do

porder order_pointer = order_impl;

and live without the said safeguard, leaving them with only a warning instead of an error in the case of a mismatch.

glglgl
  • 89,107
  • 13
  • 149
  • 217
2

You declare a function pointer just like a function, except you wrap the function name in parenthesis and write a * in front of the name.

void func (void);              // function
void (*func) (void);           // pointer to function
typedef void (*func) (void);   // pointer to function type

However, my recommended style is one that doesn't hide pointers behind a typedef:

typedef int order_t (void*, void*);
...
order_t* order; 

The typedef is a function template and the declaration is a function pointer declaration of that type. This makes function pointer syntax consistent with object pointers.

Lundin
  • 195,001
  • 40
  • 254
  • 396