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.
Why is typedef used? The syntax looks odd; after void should there not be a function name or something? It looks like an anonymous function. 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?
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)
using FunctionFunc = void(void);
*
is a bit more explicit.
myFuncPtr()
and (*myFuncPtr)()
are both valid function calls.
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
typedef is used to alias types; in this case you're aliasing FunctionFunc to void(*)(). Indeed the syntax does look odd, have a look at this: typedef void (*FunctionFunc) ( ); // ^ ^ ^ // return type type name arguments 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"
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.
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.
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)>;
using
keyword would be like typedef std::function<void(int, std::string)> FunctionFunc;
, just in case someone wants another wrapper around functions without C++11
#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) );
}
typedef (*double) p
, is the '&' optional?
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 *<pointer name> 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.
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.
Success story sharing
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?square
and&square
(and, indeed,*square
and**square
) all refer to the same function pointer.typedef int newname
, you are makingnewname
into an alias forint
. Withtypedef int (*func)(int)
, you are makingfunc
into an alias forint (*)(int)
— a pointer to function taking anint
argument and returning anint
value.int (*func)(int)
, I understand that func is an alias, just a little confused because the alias is tangled with the type. Going bytypedef int INT
as an example I would be more of ease if typedef function pointer was of formtypedef int(*function)(int) FUNC_1
. That way I can see the type and alias in two separate token instead of being meshed into one.