This question already has answers here:
How do function pointers in C work?
(12 answers)
Closed 6 years ago.
I came across the following code:
int H3I_hook(int (*progress_fn)(int*), int *id)
{
...
}
I don't understand the purpose of (int*) at the end of the first argument?
Demystifying:
int (*progress_fn)(int*)
it can be interpreted like below:
int (*progress_fn)(int*)
^ ^ ^
| | |___________ pointer to integer as argument
| |
| pointer to any function that has V and takes ^
|
|__________________________return type an integer
int (*progress_fn)(int*) is function pointer decleration, and (int *) is the list of parameters the function accepts.
So, this:
int (*progress_fn)(int*)
is a pointer to a function that will return an int and will receive one parameter, of type int*.
So you have to understand that progess_fn is the actual parameter. All its relevant components define how the function's prototype is actually.
For more, read How do function pointers in C work?
Given this declarartion:
int progress_callback(int* a);
// ^ this is the (int*) you asked about
You can call H3I_hook like this:
int id = something;
int x = H3I_hook(progress_callback, &id);
Related
This question already has answers here:
Pointer to literal value
(12 answers)
Closed 4 years ago.
Given the following piece of C code:
void calc(int *value)
{
// do something with value
}
int main(void)
{
int i;
i = 10;
calc(&i);
}
Is it possible to get rid of setting up i and pass directly 10 to function calc? If yes, how can this be done?
Example of what I have in mind (which doesn't work):
calc( (int *) 10);
Nope, it's impossible to have a pointer to a constant in C.
UPD: however it seems that there is a trick using a struct compound literals syntax (thanks to #antti-haapala for the correction). Try this:
calc(&(int){10});
This question already has answers here:
char array not assignable
(4 answers)
Why are arrays not assignable in C/C++? [duplicate]
Closed 5 years ago.
having not worked with C for a while I'm stuck with passing a single struct from an array of structs to a function by reference.
The code I have looks like this:
struct Sensor {
//ROM data
char romCRC[1];
char romSerial[6];
char romFamily[1];
};
const int maxSens = 10;
void Read_ROM(struct Sensor *sens){
char ROM[10];
for (k = 0; k<8; k++){
ROM[k] = read_byte();
sens->romFamily = ROM[0];
}
}
int main(){
struct Sensor Sensors[maxSens];
Read_ROM(&Sensors[0]);
}
What I expect it to do is:
Create an array of 10 structs of type Sensor
Pass the address of the first struct to the function Read_ROM
Set the member romFamily of the struct Sensor[0] to ROM[0]
read_byte is tested and working. It does return 1 char.
When I try to compile I get this error:
#138 expression must be a modifiable lvalue
With 138 being the line number of:
sens->romFamily = ROM[0];
What is wrong here?
Arrays are not assignable in C, although you can set individual elements.
In your case you need sens->romFamily[0] = ROM[0];
But do question why you need a single element array in the first place.
In one of the answer to How do function pointers in C work? one user explains how to use function pointers in return values. Here's the code in question:
// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int
int (*functionFactory(int n))(int, int) {
printf("Got parameter %d", n);
int (*functionPtr)(int,int) = &addInt;
return functionPtr;
}
For me the way you declare the functionFactory function is very weird - it seems to me that you mix up the return type (pointer to a function) and the function name itself (functionFactory).
For example, when we write a simple function that returns a square of its argument we write something like
int square(int n){
return n*n;
}
Clearly, the type of what we return is on the left and then we write the function name and then what parameters it accepts. So when we return a pointer to a function why don't we write something like:
( int (*function)(int, int) ) functionFactory(int n) { ...
Here the return type (which is a pointer to a function) and its details (e.g. what the function that we point to returns and what it accepts as parameters) is clearly on the left separated and the name of the functionFactory function itself is to the right. To me my version seems much more logical and clear, why don't we write it like that?
This falls out of how declarator syntax works. It may help to think in terms of substitution. Here's one way to look it:
T f (); // f is a function returning T
|
v
T (*p) (); // p is a pointer to a function returning T
|
v
T (*q())(); // q is a function returning a pointer to a function returning T
So we start with the function declarator f(). Then we replace f with the pointer (*p), giving us the declarator (*p)(). Finally we replace p with the function q(), giving us the declarator (*q())().
Edit
You may hear people talk about the "spiral rule" when reading hairy declarators. While it's more of a guideline than an actual rule, it falls out of the following precedence rules:
T *a[N]; // a is an array of pointer to T
T (*a)[N]; // a is a pointer to an array of T
T *f(); // f is a function returning T
T (*f)(); // f is a pointer to a function returning T
The postfix [] and () operators have higher precedence than unary *, hence the need for parentheses when declaring pointers to arrays or functions. So when we read T (*q())();, we start from the leftmost identifier q and "spiral" outwards:
+-----------+
| +-------+ |
| | +---+ | |
| | | | | |
T ( * q ()) ()
| | | | | |
| | +-+ | |
| +-----+ |
+---------+
Breaking it down piece by piece:
q -- q is a
q() -- function returning
*q() -- pointer to
(*q())() -- function returning
T (*q())(); -- T
You cannot declare arrays of function type, nor can you declare functions to return array types:
T a[N](); // NOT ALLOWED
T f()[N]; // NOT ALLOWED
so in any combination of function and array types, a pointer will always be involved, so the spiral rule holds.
The following code declares a variable named func to be a pointer to a function that returns an int and takes two ints as parameters:
int (*func)(int, int);
This syntax mimics the syntax how functions are declared in C:
int func(int, int);
See how similar that is? In fact functions in C are just like variables pointing to functions, e.g. see this sample:
int funcA(int a, int b) { ... }
int (*funcB)(int, int) = funcA;
It plays no role through the rest of the code if you call funcA(a,b) or funcB(a,b), does it? So even though funcB is a variable and funcA a function, the truth is, there's a function somewhere in memory and funcA and funcB are both pointers to the address of the function code.
If you want to nitpick, funcA is a constant and funcB is a variable, so the compiler output for a call to funcA will be different than for funcB; also in one case it is a direct call and in one case an indirect call, as the destination of funcB can change over time. This is also what the asterisk is saying, "I'm not a function, I'm a pointer to a function".
It's important to note that in C the asterisk is always next to the variable name to mark that a pointer variable, so how else would you like to write it instead? Like this?
// Careful! Wrong!
int (int, int) *func;
Does that look more readable to you? Or maybe like that?
// Careful! Wrong!
int ()(int, int) *func;
This syntax is not very clear either and it doesn't mimic any other existing C syntax. If you work a lot with function pointers, pass them around and store them in variables, you should declare an own type for your function pointer:
#include <stdio.h>
int sum ( int a, int b ) {
return (a + b);
}
typedef int (* MathFuncType)(int, int);
MathFuncType getSumFunc ( ) {
return ∑
}
int main(void) {
MathFuncType func = getSumFunc();
printf("%d\n", func(3, 8));
return 0;
}
http://rextester.com/GEKR20461
This question already has answers here:
Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?
(5 answers)
Closed 7 years ago.
Using typedef for functions, like in the following example, are there any differences between using the address of the function or only the function?
#include <stdio.h>
int foo(int i){return i+1;}
typedef int(*mytype[2])(int);
int main(void)
{
mytype f;
f[0] = foo;
f[1] = &foo;
printf("%d %d", f[0](5), f[0](6));
return 0;
}
In the C language, functions are implicitly converted to function pointers in most contexts. Thus you see no difference between f[0] = foo and f[1] = &foo. I prefer the latter convention, but really, both are equally fine.
This question already has answers here:
Function Returning Itself
(10 answers)
Closed 8 years ago.
In C, how can I declare a function that returns a function that returns a function etc.
I.e., I want something like this
typedef A (*A)();
A a = ...
a()()()()();
I want to achieve the following C++ behavior:
struct A { A operator()() { return A(); } };
A a;
a()()()()();
You cannot return a function in C - you return a pointer to a function. If you mean to define a function which returns a pointer to a function which again returns a pointer to a function and so on, then you can use typedef to implement it.
typedef int (*f)(int);
typedef f (*g)(float);
typedef g (*h)(char);
// and so on
However, if you mean to define a function which returns a pointer to a function of its own type, then no you cannot do it because you cannot define a recursive type in C. See here for details - Function Returning Itself
The answer is "almost yes".
Take a look the the answer given by Drew McGowen in response to Function Returning Itself.
I think that answer presents code that is closest to the behavior you are trying to see.
To have a function return a function of its own type one needs to use a intermediate function type.
As by the C Standard it is allowed to cast a function variable to any other function variable and back the following approach would do:
typedef int (*T)(void); /* The type of desire. */
typedef void (*_T)(void); /* The intermediate type. */
int g(void)
{
return 42;
}
_T h(void)
{
return (_T) g;
}
int main(void)
{
T f = (T) h;
int a = f();
int b = ((T) h())();
}
a and b both get 42assigned.