561

I'm learning how to dynamically load DLL's but what I don't understand is this line

typedef void (*FunctionFunc)();

I have a few questions. If someone is able to answer them I would be grateful.

  1. Why is typedef used?
  2. The syntax looks odd; after void should there not be a function name or something? It looks like an anonymous function.
  3. Is a function pointer created to store the memory address of a function?

So I'm confused at the moment; can you clarify things for me?

Claudio
  • 10,614
  • 4
  • 31
  • 71
Jack Harvin
  • 6,605
  • 7
  • 23
  • 21
  • 7
    Take a look at the link (last section) http://www.learncpp.com/cpp-tutorial/78-function-pointers/ – enthusiasticgeek May 03 '13 at 03:28
  • 23
    Should be noted that since c++11 `using FunctionFunc = void (*)();` can be used instead. It is a bit more clear that you are just declaring a name for a type (pointer to function) – user362515 Jan 08 '16 at 11:55
  • 1
    just to add to @user362515, a bit clearer form to me is: `using FunctionFunc = void(void);` – topspin May 28 '16 at 21:15
  • 5
    @topspin IIRC these two are not the same. One is a function pointer type, the other is function type. There is implicit conversion, that's why it works, IANA(C++)L so, one can step in and correct me. In any case, if the intend is to define a pointer type I think the syntax with the `*` is a bit more explicit. – user362515 May 31 '16 at 18:11
  • 1
    Here is [a related question I asked a long time ago](https://stackoverflow.com/q/31869026/4561887) about why both `myFuncPtr()` and `(*myFuncPtr)()` are both valid function calls. – Gabriel Staples Feb 05 '22 at 02:01

6 Answers6

584

typedef is a language construct that associates a name to a type.
You use it the same way you would use the original type, for instance

typedef int myinteger;
typedef char *mystring;
typedef void (*myfunc)();

using them like

myinteger i;   // is equivalent to    int i;
mystring s;    // is the same as      char *s;
myfunc f;      // compile equally as  void (*f)();

As you can see, you could just replace the typedefed name with its definition given above.

The difficulty lies in the pointer to functions syntax and readability in C and C++, and the typedef can improve the readability of such declarations. However, the syntax is appropriate, since functions - unlike other simpler types - may have a return value and parameters, thus the sometimes lengthy and complex declaration of a pointer to function.

The readability may start to be really tricky with pointers to functions arrays, and some other even more indirect flavors.

To answer your three questions

  • Why is typedef used? To ease the reading of the code - especially for pointers to functions, or structure names.

  • The syntax looks odd (in the pointer to function declaration) That syntax is not obvious to read, at least when beginning. Using a typedef declaration instead eases the reading

  • Is a function pointer created to store the memory address of a function? Yes, a function pointer stores the address of a function. This has nothing to do with the typedef construct which only ease the writing/reading of a program ; the compiler just expands the typedef definition before compiling the actual code.

Example:

typedef int (*t_somefunc)(int,int);

int product(int u, int v) {
  return u*v;
}

t_somefunc afunc = &product;
...
int x2 = (*afunc)(123, 456); // call product() to calculate 123*456
Yun
  • 3,056
  • 6
  • 9
  • 28
Déjà vu
  • 28,223
  • 6
  • 72
  • 100
  • 7
    in the last example, wouldn't just 'square' refer to the same thing i.e pointer to the function instead of using &square. – pranavk Mar 05 '13 at 13:32
  • 3
    Question, in your first typedef example you have of the form `typedef type alias` but with function pointers there only seems to be 2 arguments, `typedef type`. Is alias defaulted to the name specified in type argument? – dchhetri May 03 '13 at 03:56
  • 3
    @pranavk: Yes, `square` and `&square` (and, indeed, `*square` and `**square`) all refer to the same function pointer. – Jonathan Leffler May 03 '13 at 03:58
  • 9
    @user814628: It is not clear quite what you're asking. With `typedef int newname`, you are making `newname` into an alias for `int`. With `typedef int (*func)(int)`, you are making `func` into an alias for `int (*)(int)` — a pointer to function taking an `int` argument and returning an `int` value. – Jonathan Leffler May 03 '13 at 04:01
  • 14
    I guess I'm just confused about the ordering. With typedef `int (*func)(int)`, I understand that func is an alias, just a little confused because the alias is tangled with the type. Going by `typedef int INT` as an example I would be more of ease if typedef function pointer was of form `typedef int(*function)(int) FUNC_1`. That way I can see the type and alias in two separate token instead of being meshed into one. – dchhetri May 03 '13 at 05:07
  • The reason the it looks like that is that `typedef` is a storage class specifier, like `extern` or `static`. You can think of it changing the storage class to type definitions. [source](http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Flanguage%2Fref%2Fclrc03sc03.htm). Thinking of it this way makes the syntax easier to remember. – Dan Dec 04 '13 at 23:47
  • 2
    Regarding "Is a function pointer created to store the memory address of a function? Yes, ", **no**, not in this code. Also, stating that the name introduced by a `typedef` is a "keyword" is incorrect. And regarding the evaluation "the syntax is appropriate", both the C and C++ language creators disagree, calling it a failed experiment. – Cheers and hth. - Alf Mar 24 '15 at 11:16
  • While a function usually just decays to a function pointer, this is not always the case. It is safer to just always use the & rather than relying on the decay always occurring. (Or you could just wait until the compiler complains and then add it - up to you :-) ) – Jon Spencer Mar 28 '17 at 20:32
  • It would be nice to talk a little bit more about the semantics of a C-style function pointer and a C++ object-oriented function pointer, specifically about how much more memory it takes in C++ and typedef just doesn't work for OO function pointers. –  May 02 '18 at 06:06
  • 1
    Note that a **function pointer is not necessarily just an "address"**. What it actually is, depends on your platform. On some platforms, it's really just the address of the first byte of the functions' machine code, on other platforms it may be something different. On the PPC platform, for instance, a function pointer was actually a pair of addresses: One gave the start of the machine code, the other the associated globals table. So `sizeof(void (*)()) == 2*sizeof(void*)`. Other platforms may use something even more strange - **function pointers are just not the same as "normal" pointers**! – cmaster - reinstate monica May 17 '19 at 07:00
  • Furthermore, google test writes `typedef` like [this](https://github.com/google/googletest/blob/master/googletest/samples/sample7_unittest.cc#L51), very weird. @ring-Ø Could you please explain some ? – Lewis Chan Aug 16 '19 at 08:48
  • awkwardly enough you can even do `typedef returntype smth()` and then declare a pointer to it like `smth* f = &somemethod` –  May 25 '20 at 11:21
221
  1. typedef is used to alias types; in this case you're aliasing FunctionFunc to void(*)().

  2. Indeed the syntax does look odd, have a look at this:

    typedef   void      (*FunctionFunc)  ( );
    //         ^                ^         ^
    //     return type      type name  arguments
    
  3. No, this simply tells the compiler that the FunctionFunc type will be a function pointer, it doesn't define one, like this:

    FunctionFunc x;
    void doSomething() { printf("Hello there\n"); }
    x = &doSomething;
    
    x(); //prints "Hello there"
    
lineil
  • 989
  • 1
  • 8
  • 10
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • 29
    `typedef` does *not* declare a new type. you can have many `typedef`-defined names of the same type, and they are *not* distinct (e.g. wrt. overloading of functions). there are some circumstances in which, with respect to how you can use the name, a `typedef`-defined name is not exactly equivalent to what it's defined as, but multiple `typedef`-defined names for the same, are equivalent. – Cheers and hth. - Alf Nov 28 '10 at 05:00
41

Without the typedef word, in C++ the declaration would declare a variable FunctionFunc of type pointer to function of no arguments, returning void.

With the typedef it instead defines FunctionFunc as a name for that type.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
21

If you can use C++11 you may want to use std::function and using keyword.

using FunctionFunc = std::function<void(int arg1, std::string arg2)>;
Halil
  • 2,076
  • 1
  • 22
  • 30
  • 2
    without C++11 `using` keyword would be like `typedef std::function FunctionFunc;`, just in case someone wants another wrapper around functions without C++11 – Top-Master Mar 11 '19 at 04:25
  • 2
    `std::function` is fundamentally something different than a function pointer and has way worse performance in exchange for other features – Post Self Jan 16 '23 at 23:19
  • Please note this disadvantage of std::function : if after that, you need to compare a FunctionFunc myFunc with the name of a normal function (or with another std::function), it will be really hard.. this is not the case if you use the classic function pointer : using FunctionFunc = void(*)(int, std::string); – kingsjester Jul 06 '23 at 13:24
5
#include <stdio.h>
#include <math.h>

/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/

// typedef a primitive data type
typedef double distance;

// typedef struct 
typedef struct{
    int x;
    int y;
} point;

//typedef an array 
typedef point points[100]; 

points ps = {0}; // ps is an array of 100 point 

// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)

// prototype a function     
distance findDistance(point, point);

int main(int argc, char const *argv[])
{
    // delcare a function pointer 
    distanceFun_p func_p;

    // initialize the function pointer with a function address
    func_p = findDistance;

    // initialize two point variables 
    point p1 = {0,0} , p2 = {1,1};

    // call the function through the pointer
    distance d = func_p(p1,p2);

    printf("the distance is %f\n", d );

    return 0;
}

distance findDistance(point p1, point p2)
{
distance xdiff =  p1.x - p2.x;
distance ydiff =  p1.y - p2.y;

return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
}
Amjad
  • 3,110
  • 2
  • 20
  • 19
  • 1
    Under what circumstances is the '&' needed? For example, do 'func_p = &findDistance' and 'func_p = findDistance' work equally well? – Donna Oct 30 '17 at 14:06
  • 1
    A function name is a pointer, so you do not need to use '&' with it. In other words, '&' is optional when function pointers are considered. However, for primitive data type you need to use the '&' to get its address. – Amjad Oct 30 '17 at 16:41
  • 1
    It has just always struck as odd that the '&' can ever be optional. If a typedef is used to create a pointer to a primitive (i.e. `typedef (*double) p`, is the '&' optional? – Donna Oct 31 '17 at 17:39
  • I think you wanted to type `typedef double* p` to define a pointer to a double. If you want to populate the `p` pointer from a primitive variable, you will need to use the '&'. A side note, we you * to dereference a pointer. The `*` is used in the function pointer to dereference the pointer (function name) and go to the block of memory where the function instructions are located. – Amjad Oct 31 '17 at 20:16
2

For general case of syntax you can look at annex A of the ANSI C standard.

In the Backus-Naur form from there, you can see that typedef has the type storage-class-specifier.

In the type declaration-specifiers you can see that you can mix many specifier types, the order of which does not matter.

For example, it is correct to say,

long typedef long a;

to define the type a as an alias for long long. So , to understand the typedef on the exhaustive use you need to consult some backus-naur form that defines the syntax (there are many correct grammars for ANSI C, not only that of ISO).

When you use typedef to define an alias for a function type you need to put the alias in the same place where you put the identifier of the function. In your case you define the type FunctionFunc as an alias for a pointer to function whose type checking is disabled at call and returning nothing.

alinsoar
  • 15,386
  • 4
  • 57
  • 74