I have the following code:
typedef void (*func_type)(int a, int b);
func_type func;
int main()
{
func = (func_type)GetProcAddress(NULL, "func");
}
This code works fine, but I would like to change func_type func; to void func(int a, int b); (because code completion shows "func_type" instead of "func" when typing the parameters).
But when I try to change this, the compiler tells me that in the main function "expression must be a modifiable lvalue". I tried to look online but did not find an answer to my problem.
Code becomes this:
typedef void (*func_type)(int a, int b);
void func(int a, int b);
int main()
{
func = (func_type)GetProcAddress(NULL, "func");
}
Functions in C behave similar to arrays. They both decay to pointers. Whenever function name is used it automatically decays to a pointer to this function. The exceptions are & and sizeof operators. Operator sizeof does not accept a function as operand. That is why foo and &foo are equivalent.
Functions itself are non-modifiable by design. Any attempt of modifying it i.e. by memcpy-ing to a function pointer is undefined behaviour.
Surprisingly, function call operator () does not take a function as operand but a pointer to a function.
Therefore, a function call
foo(1);
is actually
(&foo)(1);
Because foo decays to &foo before evaluation of the function call.
That is why one can interchangeably use functions and function pointer in function call operands.
void foo(int) { ... }
void (*bar)(int);
foo(1); // foo decays to &foo which is a function pointer
bar(2); // bar is already a function pointer
To solve the original problem I suggest keeping func be a function pointer, that initially points to some dedicated function but it can be overwritten later on:
typedef void func_type(int,int);
void default_func(int a, int b) { ... }
funt_type* func = default_func; // decays to &default_func !
int main()
{
func(1,2); // calls default_func
func = (func_type*)GetProcAddress(NULL, "func");
func(3,4); // calls func from dll/so
}
I've decided to use function types (not function pointer types) what is a bit un-orthodox. IMO, it make syntax more visually pleasing, and it is easier to parse by a human. Moreover, it is explicit about what is a pointer what is not.
typedef void (*func_type)(int a, int b); declares func_type to be a type that is a pointer to a function. Then func_type func; declares func to be a pointer. Your proposed alternative, void func(int a, int b); declares func to be a function.
Since you can assign to a pointer, func = …; works with the first declaration. Since you cannot assign to a function, func = …; does not work with the second declaration.
To declare func to be a pointer to a function without using a typedef, use void (*func)(int, int);.
Related
I've learned function pointer is used as :
double (*ptr)(double)
ptr = my_func1;
And also, using 'typedef' could be
typedef double (*func1)(double);
func1 my_func1;
But I can't understand why this code is valid below :
int main(void){
test(a);
}
void test(int f(int))
{\
int x;\
(f==a)?(x=1):(x=2);\
printf("%d",f(x));\
}
What's that int f(int)? Is it same syntax with function pointer?
I know the type int (*)int is valid, but I've never seen the type int (int).
And Also I can't understand why the syntax in the main fuction "int f(int) = func_1" is invalid but in the 'test' function's parameter int f(int) = a is valid.
Please tell me TT Thank you.
int f(int) is a function declaration.
In C, two kinds of entities cannot be passed into functions, returned from functions or assigned: arrays and functions.
If parameters of these types are declared, they are silently turned into pointers.
A parameter int f(int) is changed to mean int (*f)(int), similarly to the way a parameter int a[3] is changed to int *a.
You might see a gratuitous warning if you declare a function one way, but define it the other; e.g.:
void test(int (*)(int));
void test(int f(int))
{
}
I've seen some version of GCC warn about this, even though it is correct; the definition and declaration are 100% compatible.
Because inside test, f is declared as a pointer, it is assignable:
f = some_func
However, in a situation where int f(int) declares a function, the identifier is not assignable:
{
int f(int); // "There exists an external f function" -- okay.
f = some_func; // Error; what? You can't assign functions!
}
Outside of function parameter declarations, functions and pointers to functions are distinguished in the usual way, as are arrays and pointers.
So, I am just trying to wrap my head around "pointer function that returns a pointer to an array"... but to start off slowly, I had to understand this:
void Print(const char c){
printf("\nPrint: %c\n", c);
}
int main () {
void (*FunctionPointer)(const char);
FunctionPointer = &Print;
FunctionPointer('a');
}
Which I do - pretty easy to guess what is going on... FunctionPointer just points to the location where the Print function "resides". Instead of jumping to a specific memory address (stored on a register) of a specific function, I can now be more flexible and point to any function that I want to access.
But I am stuck with the following...
int main () {
int (*FunctionPointer())[];
}
Now it seems that the function that is pointed by FunctionPointer, can in fact return a pointer to an array of type int. The compiler accepts the second line - so far so good - and I also understand the concept... but I am getting stuck regarding the implementation.
FunctionPointer needs - once again, to point to a function. That function can indeed return a pointer that points to an array of type int... soooooo:
int *Array(){
int ar[2] = {5,6};
return ar;
}
int main () {
int (*FunctionPointer())[];
FunctionPointer = &Array;
}
However, the last piece of code is just not accepted by the compiler.... So, what gives?
With
int (*FunctionPointer())[];
you've declared FunctionPointer as a function returning a pointer to an array of int -- not a function pointer. You want
int *(*FunctionPointer)();
If you use [] here, you'll get an error, as functions can't return arrays -- arrays are not first class types -- and unlike with function parameters, arrays will not be silently converted to pointers when used as the return value of a function type. With that, you'll still get the warning
t.c:3:12: warning: function returns address of local variable [-Wreturn-local-addr]
return ar;
^~
which is pretty self-explanatory
You have declared the array of function pointers. Arrays can't be assignable. Functions can't return arrays. You might wish
int* (*FunctionPointer)();
FunctionPointer = &Array;
Function pointers are much easier when you use typedefs. You can simply use the same notation as "normal" data pointers.
// func is a function type. It has one parater and returns pointer to int
typedef int *func(const char);
// funcptr is a pointer to func
func *funcptr;
I was reading this code on a website. I am fairly new to programming so please explain in a bit more detail.
#include <stdio.h>
// A normal function with an int parameter
// and void return type
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
// fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
/* The above line is equivalent of following two
void (*fun_ptr)(int);
fun_ptr = &fun;
*/
// Invoking fun() using fun_ptr
(*fun_ptr)(10);
return 0;
}
Doubts-
I am not able to understand this type of declaration and assignment void (*fun_ptr)(int) = &fun;
I mean that if we declare a data type, then we do it like int a; and assign it as a=10; but here we are assigning it by writing (*fun_ptr)(10);. Kindly help.
Instead of this record
(*fun_ptr)(10);
you could just write
fun_ptr(10);
That is it is a function call of the function fun pointed to by the function pointer fun_ptr due to the initialization of that pointer in its declaration by the function address
void (*fun_ptr)(int) = &fun;
In turn this declaration could be written simpler like
void (*fun_ptr)(int) = fun;
because a function designator (in this case fun) used in expressions as for example an initializer is implicitly converted to pointer to the function.
You could use a typedef alias for the function type the following way
typedef void Func( int );
In this case the above declaration of the function pointer could look simpler like
Func *fun_ptr = fun;
Here is your program rewritten using a typedef for the function type of the function fun.
#include <stdio.h>
typedef void Func( int );
// Function declaration without its definition using the typedef
// This declaration is redundant and used only to demonstrate
// how a function can be declared using a typedef name
Func fun;
// Function definition. In this case you may not use the typedef name
void fun( int a )
{
printf("Value of a is %d\n", a);
}
int main(void)
{
// Declaration of a pointer to function
Func *fun_ptr = fun;
// Call of a function using a pointer to it
fun_ptr( 10 );
return 0;
}
Lets rewrite it a little bit, by using type-aliases and some comments:
// Define a type-alias names fun_pointer_type
// This type-alias is defined as a pointer (with the asterisk *) to a function,
// the function takes one int argument and returns no value (void)
typedef void (*fun_pointer_type)(int);
// Use the type-alias to define a variable, and initialize the variable
// This defines the variable fun_ptr being the type fun_pointer_type
// I.e. fun_ptr is a pointer to a function
// Initialize it to make it point to the function fun
fun_pointer_type fun_ptr = &fun;
// Now *call* the function using the function pointer
// First dereference the pointer, to get the function it points to
// Then call the function, passing the single argument 10
(*fun_ptr)(10);
Hopefully it makes things a little clearer what's going on.
Following is the meaning of two statments.
void (*fun_ptr)(int) = &fun; this is called declaring and initializing the fun_ptr in the same line , this is same as doing int a = 10;
(*fun_ptr)(10); is not assignment statement, it is invoking the function fun through function pointer fun_ptr.
you can also use typedef to create a new user defined out of function pointer and use as shown in above answer.
This is an advanced topic if you are new to programming, fun_ptr is a pointer to a function.
The declaration:
void (*fun_ptr)(int) = fun;
Means fun_ptr is a pointer to a function taking an int argument and returning void, initialize if with a pointer to the function fun. (you don't need the &)
The line:
(*fun_ptr)(10);
does not assign anything, it calls the function pointed to by fun_ptr, but is way to complex
fun_ptr(10);
As fun_ptr points to fun this is equivalant to `fun(10).
Using a function pointer has its use eg in a sort function where the comparison function is passed in as a function pointer so the sorting can be different between calls.
achieves the same thing and is much easier on the eyes.
1) I am currently trying to understand the following code, but I can't understand what void(*func)(void) means, I can understand that I am trying to save a the address of function named "function" from list0513, at void pointer func, but what does the casting (void) just before the equal sign mean?
// list0513.c
#include <dlfcn.h>
int main(void)
{
void *handle = dlopen("./list0513.so", RTLD_LAZY);
void (*func)(void) = dlsym(handle, "function");
(*func)();
dlclose (handle);
return 0;
}
According to the book, the function called "function" is called from the following script
// list0513dl.c
#include <stdio.h>
void function(void)
{
printf("Hello World\n");
}
2) but how do I make a list0513.so file? the only files I've made are .c files...
Thanks for reading this.
The declaration reads as follows:
func — func
*func — is a pointer to
(*func)( ) — a function taking
(*func)(void) — no parameters
void (*func)(void) — returning void
The func pointer is then initialized with the result of the dlsym call, which returns the address of the function ”function” in the library list0513.so.
General declaration rules for pointer types:
T *p; // p is a pointer to T
T *p[N]; // p is an array of pointer to T
T (*p)[N]; // p is a pointer to an array of T
T *f(); // f is a function returning a pointer to T
T (*f)(); // f is a pointer to a function returning T
In both declarations and expressions, the postfix [] subscript and () function call operators have higher precedence than unary *, so *f() is parsed as *(f()) (function returning pointer). To declare a pointer to an array or function, the * has to be explicitly grouped with the array or function declarator.
Declarations can get pretty complex - you can have an array of pointers to functions:
T (*a[N])(); // a is an array of pointers to functions returning T
or functions returning pointers to arrays:
T (*f())[N]; // f is a function returning a pointer to an array
or even pointers to arrays of pointers to functions returning pointers to arrays:
T (*(*(*a)[N])())[M];
You probably won’t see anything that hairy in the wild, though (unless you run across some old code of mine).
It is omitted a declare of function type. The full or expended version should like this:
// list0513.c
#include <dlfcn.h>
int main(void)
{
void *handle = dlopen("./list0513.so", RTLD_LAZY);
typedef void(*FUNC)();
FUNC func = dlsym(handle, "function");
func(); // call function
dlclose (handle);
return 0;
}
I came across the following function declaration and I am not able to understand how exactly it works:
the function is declared in the file as follows:
struct newtype {
/* some definition */
};
typedef void function1 (int* a, newtype* p);
then in another C code above declaration is used to declare another function2 as follows:
function1 function2;
void function2(int* a, newtype* p)
{
/* function definition */
}
Then function2 is used as follows:
int function3 (int, char, function1* );
/* definition */
function3(int a, char c, function2 )
{
/* function definition */
}
I am not able to understand the statement:
function1 function2;
and what does typedef void function1 (arguments) mean as function1 is not declared as a pointer. Can anyone explain what is happening here?
function1 is declared as a type for functions not returning anything and taking a pointer to an int and a pointer to a newtype as arguments.
This way is useful to make sure you get functions that conform to a particular format especially when you use callback functions / function pointers.
typedef void function1 (int* a, newtype* p);
defines the name function1 as an alias for the type void ()(int *, newtype *) i.e. a function.
Thus function1 function2; is the same as this prototype:
void function2 (int* a, newtype* p);
The name function1 could also be used to declare a pointer, which result in a familiar "function pointer". That is what function3 is doing when it declares int function3 (int, char, function1* ); - its last argument is a pointer to a function with the signature void ()(int *, newtype *)