Typedef function pointer?
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 atypedef
declaration instead eases the readingIs 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 thetypedef
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 function vs function pointer
Yes you are right on all three counts. The only thing that would change if you marked them extern
are the function pointers. Function declarations are by default extern
in C++.
Try and compile the following program
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
// constexpr auto one = WhichType<fcn_t>{};
// constexpr auto two = WhichType<fcn_t*>{};
// constexpr auto three = WhichType<ptr_t>{};
fcn_t f;
void f() {}
int main() {
f();
}
Uncommenting the commented lines will likely give you a compiler error that tells you what types the WhichType
instance is being instantiated with, and as a result it should show you the exact types of all three things you asked about. It's a trick I picked up from Scott Meyers' book "Effective Modern C++".
To test whether the declarations are extern or not, write two simple implementation files, with one containing the definition of the variable
main.cpp
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
int main() {
f();
}
definition.cpp
void f() {}
and then compile, link and run definition.cpp
and main.cpp
(via g++ -std=c++14 definition.cpp main.cpp
and then ./a.out
). If the declaration was not extern then the compile would fail with an undefined symbol error.
How to use typedef to an array of function pointers
It is generally cleaner to typedef function types, not function pointers. It results in cleaner syntax:
typedef int collection_f(int, int);
Now you can define collection
, simply as an array of pointer to collection_f
.
collection_f* collection[2] = {&fct1,&fct2};
A typical call syntax would be:
collection[0](1,2);
collection[1](1,2);
Don't de-reference function pointer prior to calling. Actually, call operator takes a function pointer as an operand, not a function. Functions decay to function pointer in all context except &
operator ... which returns a function pointer.
Next, I'm not sure what:
alternateName p = &collection[2];
is supposed to mean. I assume that you want p
to point to the first element of collection
. Moreover, indexing p[1]
and p[2]
looks like out of bound access because accessing collection is only defined for indices 0 and 1.
Now your code could be rewritten can:
collection_f** p = collection; // pointer to first element which is a pointer to collection_f
int result1 = p[0](1,2);
int result2 = p[1](1,2);
printf("results are: %d, %d",result1, result2);
I hope it fixes the problem.
How to define function type with typedef?
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 *);
C function pointer and typedef
The callback function will be called from the myFunction
. You have to pass just your callback function as a parameter. Here's an example:
#include <stdio.h>
typedef void (f_Callback)(int a,
int b,
int c);
int myFunction(int a, f_Callback* callback)
{
callback(a, a+1, a+2);
}
void myCallback(int a, int b, int c)
{
printf("a: %d, b: %d, c: %d\n", a, b, c);
}
int main()
{
myFunction(5, &myCallback);
return 0;
}
Expected output:
$./a.out
a: 5, b: 6, c: 7
How to create a typedef for function pointers
Your question isn't clear, but I think you might want something like this:
int foo(int i){ return i + 1;}
typedef int (*g)(int); // Declare typedef
g func = &foo; // Define function-pointer variable, and initialise
int hvar = func(3); // Call function through pointer
How to typedef template function pointer?
As @HolyBlackCat pointed out, the normal function pointer should work as you have a simple templated void function, whose template parameter does not act on both return and argument types.
template <typename T>
void someVoidFunction() {}
using fPtrType = void(*)();
int main()
{
fPtrType funPtr1 = &someVoidFunction<int>;
fPtrType funPtr2 = &someVoidFunction<float>;
fPtrType funPtr3 = &someVoidFunction<std::string>;
return 0;
}
If it was the case, that template parameters depends on the function arg and return types you should have instantiated the function pointer as well for each kind.
template <typename T, typename U>
T someFunction(U u) {}
template <typename T, typename U>
using fPtrType = T(*)(U);
int main()
{
fPtrType<int, float> funPtr1 = &someFunction<int, float>; // instance 1
fPtrType<float, float> funPtr2 = &someFunction<float, float>; // instance 2
return 0;
}
how to understand using typedef to define a function pointer?
Let's start by talking about declaration syntax in general (I'll be using C terminology, although C++ is largely similar). In both C and C++, a declaration contains a sequence of one or more declaration specifiers followed by a comma-separated list of zero or more declarators.
Declaration specifiers include type specifiers (int
, double
, char
, unsigned
, etc.), type qualifiers (const
, volatile
, etc.), storage class specifiers (static
, register
, typedef
, etc.), struct
and union
specifiers, and a few other things we won't get into here.
Declarators include the name of the thing being declared, along with information about that thing's pointer-ness, array-ness, or function-ness (in C++ you also have reference-ness).
When you declare a function, such as
void foo( int, double );
void
is the declaration specifier (type specifier), and foo( int, double )
is the declarator. The type of foo
is fully specified by the combination of the declaration specifier and declarator:
foo -- foo
foo( ) -- is a function taking
foo( ) -- unnamed parameter
foo( int ) -- is an int
foo( int, ) -- unnamed parameter
foo( int, double ) -- is a double
void foo( int, double ) -- returning void
In plain English, the type of foo
is "function taking an int
and double
parameter and returning void
."
You can declare pointers to functions as well:
fptr -- fptr
(*fptr) -- is a pointer to
(*fptr)( ) -- function taking
(*fptr)( ) -- unnamed parameter
(*fptr)( int ) -- is an int
(*fptr)( int, ) -- unnamed parameter
(*fptr)( int, double ) -- is a double
void (*fptr)( int, double ) -- returning void
Again, the sole declaration specifier is void
, and the declarator is (*fptr)( int, double )
.
For syntactic purposes, typedef
is grouped with the storage class specifiers (static
, auto
, register
), but it doesn't behave like other storage class specifiers - instead of affecting the storage or visibility of the thing being declared, it makes the identifier in the declarator an alias for the type. If we stick typedef
on the front of the above declaration:
typedef void (*fptr)( int, double );
then it reads as
fptr -- fptr
typedef fptr -- IS AN ALIAS FOR THE TYPE
typedef (*fptr) -- pointer to
typedef (*fptr)( ) -- function taking
typedef (*fptr)( ) -- unnamed parameter
typedef (*fptr)( int ) -- is an int
typedef (*fptr)( int, ) -- unnamed parameter
typedef (*fptr)( int, double ) -- is a double
typedef void (*fptr)( int, double ) -- returning void
IOW, fptr
is an alias (typedef
name) for the type "pointer to function taking an int
and double
parameter and returning void
", and you can use it to declare pointer objects of that type:
fptr fp1, fp2;
You can do the same thing with other pointer types1:
typedef int *intp; // intp is an alias for the type "pointer to int";
typedef double (*arr)[10]; // arr is an alias for the type "pointer to 10-element array of double"
Declarators can get pretty complex. You can have pointers to functions:
T (*ptr)();
pointers to arrays:
T (*ptr)[N];
arrays of pointers to functions:
T (*ptr[N])();
functions returning pointers to arrays:
T (*foo())[N];
arrays of pointers to functions returning pointers to arrays:
T (*(*arr[N])())[M];
and on and on and on, and sticking typedef
in front of any of them will work:
typedef T (*(*arr[N])())[M];
means arr
is an alias for the type "N-element array of pointers to functions returning pointers to M-element arrays of T
".
- As a rule, you do not want to hide pointers to scalar types behind typedefs unless you can guarantee that the programmer using that type will never have to be aware of the underlying pointer-ness of that type (i.e., will never have to explicitly dereference it with
*
or try to print its value with%p
or anything like that).
How to call a macro with a typedef function pointer in C?
Given #define FPTR_MACRO ((fptr)0x1234)
, you can call the function with FPTR_MACRO(1, 1)
.
However, this will only work if 0x1234 is a correct address for the function. If that is not actually the address of the function, but rather is “the address where the reference to fptr will exist”, meaning that 0x1234 is the address where a pointer to the function is, then the macro is incorrect. Instead, you need to get the pointer from the location, as with * (fptr **) 0x1234
, and then you can call the function using that pointer, as with (* (fptr **) 0x1234) (1, 1)
.
Note that the expression used to call a function is a pointer, not a function. When we have f(x, y)
, the operand f
should actually be a pointer to a function, not a function, per C 2018 6.5.2.2 1. When we do write a function name there, such as pow(x, y)
, the function is automatically converted to a pointer, as if we had written (&pow)(x, y)
. This is what allows us to write function calls “naturally.” What this means is that, when you already have a pointer, such as FPTR_MACRO
, you do not need anything special to call the function. You already have the required pointer, so you can call it with just FPTR_MACRO(1, 1)
.
Related Topics
How to Print a Double Value With Full Precision Using Cout
Sorting a Vector of Custom Objects
How to Best Silence a Warning About Unused Variables
When How to Use a Forward Declaration
The Definitive C++ Book Guide and List
Why Should C++ Programmers Minimize Use of 'New'
What Are the Basic Rules and Idioms For Operator Overloading
Undefined Behavior and Sequence Points
How Does the Comma Operator Work
Why Does Std::Getline() Skip Input After a Formatted Extraction
What Does the C++ Standard State the Size of Int, Long Type to Be
Why Isn't Sizeof For a Struct Equal to the Sum of Sizeof of Each Member
How Does the Compilation/Linking Process Work
C++ Preprocessor _Va_Args_ Number of Arguments