Correct value type for function pointers in C
I was trying to understand function pointers in C. While reading about it on internet (mostly stack overflow QAs) - I came across 2 ways in which I can assign value to a function pointer
#include <stdio.h>
double add(int a, double b) {
return a + b;
}
double subtract(int a, double b) {
return a - b;
}
int main() {
int op_a = 23;
double op_b = 2.9;
// Case 1. Just pass the function (not its address)
double (*math_op)(int a, double b) = add;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
// Case 2. Pass the function's address
math_op = &subtract;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
printf("End of programn");
return 0;
}
I have couple of questions
- In the code above - what is the right way to assign value value to function pointer. I see several answers on stack overflow which follow the convention followed in case 1, and I also see some answers following convention in case 2. Both seem to be working correctly for me. Which is one is correct (or preferable)?
- Also, in order to call function pointers I see 2 ways in which you can call them -
math_op(op_a, op_b)
or(*math_op)(op_a, op_b)
. Again, is there a preferable way of doing this - both seem to be working correctly for me.
c function-pointers
add a comment |
I was trying to understand function pointers in C. While reading about it on internet (mostly stack overflow QAs) - I came across 2 ways in which I can assign value to a function pointer
#include <stdio.h>
double add(int a, double b) {
return a + b;
}
double subtract(int a, double b) {
return a - b;
}
int main() {
int op_a = 23;
double op_b = 2.9;
// Case 1. Just pass the function (not its address)
double (*math_op)(int a, double b) = add;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
// Case 2. Pass the function's address
math_op = &subtract;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
printf("End of programn");
return 0;
}
I have couple of questions
- In the code above - what is the right way to assign value value to function pointer. I see several answers on stack overflow which follow the convention followed in case 1, and I also see some answers following convention in case 2. Both seem to be working correctly for me. Which is one is correct (or preferable)?
- Also, in order to call function pointers I see 2 ways in which you can call them -
math_op(op_a, op_b)
or(*math_op)(op_a, op_b)
. Again, is there a preferable way of doing this - both seem to be working correctly for me.
c function-pointers
It doesn't matter, but I would suggest being consistent throughout your code with the method you do choose to go with, not mix and match
– M.M
Nov 22 '18 at 21:22
!Nishant Note: posted code lacks a declaration ofmath_op
and a 1st case assignment. Suggest adding these your post for clarity.
– chux
Nov 23 '18 at 3:07
add a comment |
I was trying to understand function pointers in C. While reading about it on internet (mostly stack overflow QAs) - I came across 2 ways in which I can assign value to a function pointer
#include <stdio.h>
double add(int a, double b) {
return a + b;
}
double subtract(int a, double b) {
return a - b;
}
int main() {
int op_a = 23;
double op_b = 2.9;
// Case 1. Just pass the function (not its address)
double (*math_op)(int a, double b) = add;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
// Case 2. Pass the function's address
math_op = &subtract;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
printf("End of programn");
return 0;
}
I have couple of questions
- In the code above - what is the right way to assign value value to function pointer. I see several answers on stack overflow which follow the convention followed in case 1, and I also see some answers following convention in case 2. Both seem to be working correctly for me. Which is one is correct (or preferable)?
- Also, in order to call function pointers I see 2 ways in which you can call them -
math_op(op_a, op_b)
or(*math_op)(op_a, op_b)
. Again, is there a preferable way of doing this - both seem to be working correctly for me.
c function-pointers
I was trying to understand function pointers in C. While reading about it on internet (mostly stack overflow QAs) - I came across 2 ways in which I can assign value to a function pointer
#include <stdio.h>
double add(int a, double b) {
return a + b;
}
double subtract(int a, double b) {
return a - b;
}
int main() {
int op_a = 23;
double op_b = 2.9;
// Case 1. Just pass the function (not its address)
double (*math_op)(int a, double b) = add;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
// Case 2. Pass the function's address
math_op = &subtract;
printf("The output of Math Operation %fn", math_op(op_a, op_b));
printf("End of programn");
return 0;
}
I have couple of questions
- In the code above - what is the right way to assign value value to function pointer. I see several answers on stack overflow which follow the convention followed in case 1, and I also see some answers following convention in case 2. Both seem to be working correctly for me. Which is one is correct (or preferable)?
- Also, in order to call function pointers I see 2 ways in which you can call them -
math_op(op_a, op_b)
or(*math_op)(op_a, op_b)
. Again, is there a preferable way of doing this - both seem to be working correctly for me.
c function-pointers
c function-pointers
asked Nov 22 '18 at 21:07
NishantNishant
159513
159513
It doesn't matter, but I would suggest being consistent throughout your code with the method you do choose to go with, not mix and match
– M.M
Nov 22 '18 at 21:22
!Nishant Note: posted code lacks a declaration ofmath_op
and a 1st case assignment. Suggest adding these your post for clarity.
– chux
Nov 23 '18 at 3:07
add a comment |
It doesn't matter, but I would suggest being consistent throughout your code with the method you do choose to go with, not mix and match
– M.M
Nov 22 '18 at 21:22
!Nishant Note: posted code lacks a declaration ofmath_op
and a 1st case assignment. Suggest adding these your post for clarity.
– chux
Nov 23 '18 at 3:07
It doesn't matter, but I would suggest being consistent throughout your code with the method you do choose to go with, not mix and match
– M.M
Nov 22 '18 at 21:22
It doesn't matter, but I would suggest being consistent throughout your code with the method you do choose to go with, not mix and match
– M.M
Nov 22 '18 at 21:22
!Nishant Note: posted code lacks a declaration of
math_op
and a 1st case assignment. Suggest adding these your post for clarity.– chux
Nov 23 '18 at 3:07
!Nishant Note: posted code lacks a declaration of
math_op
and a 1st case assignment. Suggest adding these your post for clarity.– chux
Nov 23 '18 at 3:07
add a comment |
3 Answers
3
active
oldest
votes
I think
Function calls (§6.5.2.2/1):
The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.
is enough to answer both of your questions. The name of a function is implicitly converted to pointer to function type so using the address-of operator when assigning the adress of a function to a function pointer is superfluous. As for calling functions by function pointers the syntax is no different from "ordinary" function calls.
add a comment |
This is really a quirk of C. The *
and (a single) &
are kind of ignored when taking an address of a function.
int main() {
printf("%p %p %p", (void*)add, (void*)************add, (void*)&add);
}
The *
are ignored when "dereferencing" a function pointer
int main() {
double (*math_op)(int a, double b) = add;
printf("%p %p %f", (void*)math_op, (void*)*************math_op, (***************math_op)(1, 1.0));
}
It does not matter. However be consistent. Mostly I saw no *
nor &
used in such contexts.
add a comment |
Case 1 is preferred.
The &
is optional to take the address of a function (just like: char buf[100]; char *bp = buf;
)
The reason case 1 is preferred is that the syntax is the same for assignment to a function pointer from a function address or another function pointer:
typedef double (*math_func)(int a, double b);
math_func math_op = add;
math_func math_op2 = sub;
math_func math_op3 = math_op2;
Analogously, that's why you can say: math_op(2,23)
as a shorthand for: (*math_op)(2,23)
UPDATE:
Pointer typedefs are not preferred (by me anyway)
They certainly help for function pointers [which Jonathan Leffler makes an exception for].
If you had (e.g.) 10 functions that needed to take an argument that was a function pointer, would you want to spell it out in all 10 function prototypes, particularly if the function pointer took 8 arguments itself?
Suppose [in some API] you had a function pointer:
typedef void (*funcptr)(int x,int y,int z);
Consider that you had functions of the form:
void func(funcptr f,...);
And, you had a call chain of these functions:
a -> b -> c -> d -> apiabc
Functions a-d
do not call f
--only apiabc
does. Only apiabc
has knowledge of how to call f
properly. The others are merely passing along the opaque [to them] pointer so that apiabc
can act on it.
If funcptr
ever had to change, changing a-d
would be problematic (i.e. they are not part of the API--merely users of it).
On pointer typedef
s in general, IMO, they are fine if they are reasonably obvious and consistent.
This would be an example of usages:
typedef struct node *Node; // poor
typedef struct node *pNode; // MS (common but, IMO, poor)
typedef struct node *nodeP; // okay
typedef struct node *nodeptr; // better?
typedef const struct node *nodecptr; // better?
IMO, the MS version is poor because if we sorted all names pNode
would get intermixed with all [unrelated] pWhatever
and not gravitate to node
whereas looking left to right nodeP
has the dominant part first (i.e. it's related to a node).
IMO, it is hubris for POSIX to lay claim to whatever_t
as its province for type names. But, it's low probability that there will be a collision [for me, anyway, because I always use names that are likely to not conflict]. If there is a collision based on a future POSIX type, I lose, and have to change my definitions.
Thus, my personal conventions are:
typedef struct node node_t;
typedef node_t *node_p;
typedef const node_t *node_pc;
Any such convention can be used so long as it's applied consistently. In a given set of code, if one encounters foo_p
for the first time, yes, one has to look in the .h
file for the definition. After that, when one sees bar_p
, the convention is already known.
For me, this usually isn't a problem, because when I encounter an unfamiliar code base, I always look at the definitions in the .h
file before looking at code in a .c
1
Pointer typedefs are not preferred (by me anyway)
– M.M
Nov 22 '18 at 21:32
@M.M Granted, this is a bit of personal style/preference. I've added an update to my answer (too long for a comment) that lays out how I use pointer typedefs and why. See what you think ...
– Craig Estey
Nov 22 '18 at 23:28
1
False dichotomy, you compare pointer typedef with not using typedef at all... I would use a non-pointer typedef.typedef double math_func(int a, double b); math_func add, sub; /* ... */ math_func *math_op = add;
. Later on you recommendnode_p
with the comment "one has to look in the .h file for the definition". However if you just usednode_t *
then nothing needs to be looked up
– M.M
Nov 22 '18 at 23:46
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437993%2fcorrect-value-type-for-function-pointers-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think
Function calls (§6.5.2.2/1):
The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.
is enough to answer both of your questions. The name of a function is implicitly converted to pointer to function type so using the address-of operator when assigning the adress of a function to a function pointer is superfluous. As for calling functions by function pointers the syntax is no different from "ordinary" function calls.
add a comment |
I think
Function calls (§6.5.2.2/1):
The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.
is enough to answer both of your questions. The name of a function is implicitly converted to pointer to function type so using the address-of operator when assigning the adress of a function to a function pointer is superfluous. As for calling functions by function pointers the syntax is no different from "ordinary" function calls.
add a comment |
I think
Function calls (§6.5.2.2/1):
The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.
is enough to answer both of your questions. The name of a function is implicitly converted to pointer to function type so using the address-of operator when assigning the adress of a function to a function pointer is superfluous. As for calling functions by function pointers the syntax is no different from "ordinary" function calls.
I think
Function calls (§6.5.2.2/1):
The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.
is enough to answer both of your questions. The name of a function is implicitly converted to pointer to function type so using the address-of operator when assigning the adress of a function to a function pointer is superfluous. As for calling functions by function pointers the syntax is no different from "ordinary" function calls.
edited Nov 22 '18 at 22:07
answered Nov 22 '18 at 21:19
SwordfishSwordfish
1
1
add a comment |
add a comment |
This is really a quirk of C. The *
and (a single) &
are kind of ignored when taking an address of a function.
int main() {
printf("%p %p %p", (void*)add, (void*)************add, (void*)&add);
}
The *
are ignored when "dereferencing" a function pointer
int main() {
double (*math_op)(int a, double b) = add;
printf("%p %p %f", (void*)math_op, (void*)*************math_op, (***************math_op)(1, 1.0));
}
It does not matter. However be consistent. Mostly I saw no *
nor &
used in such contexts.
add a comment |
This is really a quirk of C. The *
and (a single) &
are kind of ignored when taking an address of a function.
int main() {
printf("%p %p %p", (void*)add, (void*)************add, (void*)&add);
}
The *
are ignored when "dereferencing" a function pointer
int main() {
double (*math_op)(int a, double b) = add;
printf("%p %p %f", (void*)math_op, (void*)*************math_op, (***************math_op)(1, 1.0));
}
It does not matter. However be consistent. Mostly I saw no *
nor &
used in such contexts.
add a comment |
This is really a quirk of C. The *
and (a single) &
are kind of ignored when taking an address of a function.
int main() {
printf("%p %p %p", (void*)add, (void*)************add, (void*)&add);
}
The *
are ignored when "dereferencing" a function pointer
int main() {
double (*math_op)(int a, double b) = add;
printf("%p %p %f", (void*)math_op, (void*)*************math_op, (***************math_op)(1, 1.0));
}
It does not matter. However be consistent. Mostly I saw no *
nor &
used in such contexts.
This is really a quirk of C. The *
and (a single) &
are kind of ignored when taking an address of a function.
int main() {
printf("%p %p %p", (void*)add, (void*)************add, (void*)&add);
}
The *
are ignored when "dereferencing" a function pointer
int main() {
double (*math_op)(int a, double b) = add;
printf("%p %p %f", (void*)math_op, (void*)*************math_op, (***************math_op)(1, 1.0));
}
It does not matter. However be consistent. Mostly I saw no *
nor &
used in such contexts.
answered Nov 22 '18 at 21:27
Kamil CukKamil Cuk
12k1529
12k1529
add a comment |
add a comment |
Case 1 is preferred.
The &
is optional to take the address of a function (just like: char buf[100]; char *bp = buf;
)
The reason case 1 is preferred is that the syntax is the same for assignment to a function pointer from a function address or another function pointer:
typedef double (*math_func)(int a, double b);
math_func math_op = add;
math_func math_op2 = sub;
math_func math_op3 = math_op2;
Analogously, that's why you can say: math_op(2,23)
as a shorthand for: (*math_op)(2,23)
UPDATE:
Pointer typedefs are not preferred (by me anyway)
They certainly help for function pointers [which Jonathan Leffler makes an exception for].
If you had (e.g.) 10 functions that needed to take an argument that was a function pointer, would you want to spell it out in all 10 function prototypes, particularly if the function pointer took 8 arguments itself?
Suppose [in some API] you had a function pointer:
typedef void (*funcptr)(int x,int y,int z);
Consider that you had functions of the form:
void func(funcptr f,...);
And, you had a call chain of these functions:
a -> b -> c -> d -> apiabc
Functions a-d
do not call f
--only apiabc
does. Only apiabc
has knowledge of how to call f
properly. The others are merely passing along the opaque [to them] pointer so that apiabc
can act on it.
If funcptr
ever had to change, changing a-d
would be problematic (i.e. they are not part of the API--merely users of it).
On pointer typedef
s in general, IMO, they are fine if they are reasonably obvious and consistent.
This would be an example of usages:
typedef struct node *Node; // poor
typedef struct node *pNode; // MS (common but, IMO, poor)
typedef struct node *nodeP; // okay
typedef struct node *nodeptr; // better?
typedef const struct node *nodecptr; // better?
IMO, the MS version is poor because if we sorted all names pNode
would get intermixed with all [unrelated] pWhatever
and not gravitate to node
whereas looking left to right nodeP
has the dominant part first (i.e. it's related to a node).
IMO, it is hubris for POSIX to lay claim to whatever_t
as its province for type names. But, it's low probability that there will be a collision [for me, anyway, because I always use names that are likely to not conflict]. If there is a collision based on a future POSIX type, I lose, and have to change my definitions.
Thus, my personal conventions are:
typedef struct node node_t;
typedef node_t *node_p;
typedef const node_t *node_pc;
Any such convention can be used so long as it's applied consistently. In a given set of code, if one encounters foo_p
for the first time, yes, one has to look in the .h
file for the definition. After that, when one sees bar_p
, the convention is already known.
For me, this usually isn't a problem, because when I encounter an unfamiliar code base, I always look at the definitions in the .h
file before looking at code in a .c
1
Pointer typedefs are not preferred (by me anyway)
– M.M
Nov 22 '18 at 21:32
@M.M Granted, this is a bit of personal style/preference. I've added an update to my answer (too long for a comment) that lays out how I use pointer typedefs and why. See what you think ...
– Craig Estey
Nov 22 '18 at 23:28
1
False dichotomy, you compare pointer typedef with not using typedef at all... I would use a non-pointer typedef.typedef double math_func(int a, double b); math_func add, sub; /* ... */ math_func *math_op = add;
. Later on you recommendnode_p
with the comment "one has to look in the .h file for the definition". However if you just usednode_t *
then nothing needs to be looked up
– M.M
Nov 22 '18 at 23:46
add a comment |
Case 1 is preferred.
The &
is optional to take the address of a function (just like: char buf[100]; char *bp = buf;
)
The reason case 1 is preferred is that the syntax is the same for assignment to a function pointer from a function address or another function pointer:
typedef double (*math_func)(int a, double b);
math_func math_op = add;
math_func math_op2 = sub;
math_func math_op3 = math_op2;
Analogously, that's why you can say: math_op(2,23)
as a shorthand for: (*math_op)(2,23)
UPDATE:
Pointer typedefs are not preferred (by me anyway)
They certainly help for function pointers [which Jonathan Leffler makes an exception for].
If you had (e.g.) 10 functions that needed to take an argument that was a function pointer, would you want to spell it out in all 10 function prototypes, particularly if the function pointer took 8 arguments itself?
Suppose [in some API] you had a function pointer:
typedef void (*funcptr)(int x,int y,int z);
Consider that you had functions of the form:
void func(funcptr f,...);
And, you had a call chain of these functions:
a -> b -> c -> d -> apiabc
Functions a-d
do not call f
--only apiabc
does. Only apiabc
has knowledge of how to call f
properly. The others are merely passing along the opaque [to them] pointer so that apiabc
can act on it.
If funcptr
ever had to change, changing a-d
would be problematic (i.e. they are not part of the API--merely users of it).
On pointer typedef
s in general, IMO, they are fine if they are reasonably obvious and consistent.
This would be an example of usages:
typedef struct node *Node; // poor
typedef struct node *pNode; // MS (common but, IMO, poor)
typedef struct node *nodeP; // okay
typedef struct node *nodeptr; // better?
typedef const struct node *nodecptr; // better?
IMO, the MS version is poor because if we sorted all names pNode
would get intermixed with all [unrelated] pWhatever
and not gravitate to node
whereas looking left to right nodeP
has the dominant part first (i.e. it's related to a node).
IMO, it is hubris for POSIX to lay claim to whatever_t
as its province for type names. But, it's low probability that there will be a collision [for me, anyway, because I always use names that are likely to not conflict]. If there is a collision based on a future POSIX type, I lose, and have to change my definitions.
Thus, my personal conventions are:
typedef struct node node_t;
typedef node_t *node_p;
typedef const node_t *node_pc;
Any such convention can be used so long as it's applied consistently. In a given set of code, if one encounters foo_p
for the first time, yes, one has to look in the .h
file for the definition. After that, when one sees bar_p
, the convention is already known.
For me, this usually isn't a problem, because when I encounter an unfamiliar code base, I always look at the definitions in the .h
file before looking at code in a .c
1
Pointer typedefs are not preferred (by me anyway)
– M.M
Nov 22 '18 at 21:32
@M.M Granted, this is a bit of personal style/preference. I've added an update to my answer (too long for a comment) that lays out how I use pointer typedefs and why. See what you think ...
– Craig Estey
Nov 22 '18 at 23:28
1
False dichotomy, you compare pointer typedef with not using typedef at all... I would use a non-pointer typedef.typedef double math_func(int a, double b); math_func add, sub; /* ... */ math_func *math_op = add;
. Later on you recommendnode_p
with the comment "one has to look in the .h file for the definition". However if you just usednode_t *
then nothing needs to be looked up
– M.M
Nov 22 '18 at 23:46
add a comment |
Case 1 is preferred.
The &
is optional to take the address of a function (just like: char buf[100]; char *bp = buf;
)
The reason case 1 is preferred is that the syntax is the same for assignment to a function pointer from a function address or another function pointer:
typedef double (*math_func)(int a, double b);
math_func math_op = add;
math_func math_op2 = sub;
math_func math_op3 = math_op2;
Analogously, that's why you can say: math_op(2,23)
as a shorthand for: (*math_op)(2,23)
UPDATE:
Pointer typedefs are not preferred (by me anyway)
They certainly help for function pointers [which Jonathan Leffler makes an exception for].
If you had (e.g.) 10 functions that needed to take an argument that was a function pointer, would you want to spell it out in all 10 function prototypes, particularly if the function pointer took 8 arguments itself?
Suppose [in some API] you had a function pointer:
typedef void (*funcptr)(int x,int y,int z);
Consider that you had functions of the form:
void func(funcptr f,...);
And, you had a call chain of these functions:
a -> b -> c -> d -> apiabc
Functions a-d
do not call f
--only apiabc
does. Only apiabc
has knowledge of how to call f
properly. The others are merely passing along the opaque [to them] pointer so that apiabc
can act on it.
If funcptr
ever had to change, changing a-d
would be problematic (i.e. they are not part of the API--merely users of it).
On pointer typedef
s in general, IMO, they are fine if they are reasonably obvious and consistent.
This would be an example of usages:
typedef struct node *Node; // poor
typedef struct node *pNode; // MS (common but, IMO, poor)
typedef struct node *nodeP; // okay
typedef struct node *nodeptr; // better?
typedef const struct node *nodecptr; // better?
IMO, the MS version is poor because if we sorted all names pNode
would get intermixed with all [unrelated] pWhatever
and not gravitate to node
whereas looking left to right nodeP
has the dominant part first (i.e. it's related to a node).
IMO, it is hubris for POSIX to lay claim to whatever_t
as its province for type names. But, it's low probability that there will be a collision [for me, anyway, because I always use names that are likely to not conflict]. If there is a collision based on a future POSIX type, I lose, and have to change my definitions.
Thus, my personal conventions are:
typedef struct node node_t;
typedef node_t *node_p;
typedef const node_t *node_pc;
Any such convention can be used so long as it's applied consistently. In a given set of code, if one encounters foo_p
for the first time, yes, one has to look in the .h
file for the definition. After that, when one sees bar_p
, the convention is already known.
For me, this usually isn't a problem, because when I encounter an unfamiliar code base, I always look at the definitions in the .h
file before looking at code in a .c
Case 1 is preferred.
The &
is optional to take the address of a function (just like: char buf[100]; char *bp = buf;
)
The reason case 1 is preferred is that the syntax is the same for assignment to a function pointer from a function address or another function pointer:
typedef double (*math_func)(int a, double b);
math_func math_op = add;
math_func math_op2 = sub;
math_func math_op3 = math_op2;
Analogously, that's why you can say: math_op(2,23)
as a shorthand for: (*math_op)(2,23)
UPDATE:
Pointer typedefs are not preferred (by me anyway)
They certainly help for function pointers [which Jonathan Leffler makes an exception for].
If you had (e.g.) 10 functions that needed to take an argument that was a function pointer, would you want to spell it out in all 10 function prototypes, particularly if the function pointer took 8 arguments itself?
Suppose [in some API] you had a function pointer:
typedef void (*funcptr)(int x,int y,int z);
Consider that you had functions of the form:
void func(funcptr f,...);
And, you had a call chain of these functions:
a -> b -> c -> d -> apiabc
Functions a-d
do not call f
--only apiabc
does. Only apiabc
has knowledge of how to call f
properly. The others are merely passing along the opaque [to them] pointer so that apiabc
can act on it.
If funcptr
ever had to change, changing a-d
would be problematic (i.e. they are not part of the API--merely users of it).
On pointer typedef
s in general, IMO, they are fine if they are reasonably obvious and consistent.
This would be an example of usages:
typedef struct node *Node; // poor
typedef struct node *pNode; // MS (common but, IMO, poor)
typedef struct node *nodeP; // okay
typedef struct node *nodeptr; // better?
typedef const struct node *nodecptr; // better?
IMO, the MS version is poor because if we sorted all names pNode
would get intermixed with all [unrelated] pWhatever
and not gravitate to node
whereas looking left to right nodeP
has the dominant part first (i.e. it's related to a node).
IMO, it is hubris for POSIX to lay claim to whatever_t
as its province for type names. But, it's low probability that there will be a collision [for me, anyway, because I always use names that are likely to not conflict]. If there is a collision based on a future POSIX type, I lose, and have to change my definitions.
Thus, my personal conventions are:
typedef struct node node_t;
typedef node_t *node_p;
typedef const node_t *node_pc;
Any such convention can be used so long as it's applied consistently. In a given set of code, if one encounters foo_p
for the first time, yes, one has to look in the .h
file for the definition. After that, when one sees bar_p
, the convention is already known.
For me, this usually isn't a problem, because when I encounter an unfamiliar code base, I always look at the definitions in the .h
file before looking at code in a .c
edited Nov 22 '18 at 23:24
answered Nov 22 '18 at 21:27
Craig EsteyCraig Estey
15.2k21130
15.2k21130
1
Pointer typedefs are not preferred (by me anyway)
– M.M
Nov 22 '18 at 21:32
@M.M Granted, this is a bit of personal style/preference. I've added an update to my answer (too long for a comment) that lays out how I use pointer typedefs and why. See what you think ...
– Craig Estey
Nov 22 '18 at 23:28
1
False dichotomy, you compare pointer typedef with not using typedef at all... I would use a non-pointer typedef.typedef double math_func(int a, double b); math_func add, sub; /* ... */ math_func *math_op = add;
. Later on you recommendnode_p
with the comment "one has to look in the .h file for the definition". However if you just usednode_t *
then nothing needs to be looked up
– M.M
Nov 22 '18 at 23:46
add a comment |
1
Pointer typedefs are not preferred (by me anyway)
– M.M
Nov 22 '18 at 21:32
@M.M Granted, this is a bit of personal style/preference. I've added an update to my answer (too long for a comment) that lays out how I use pointer typedefs and why. See what you think ...
– Craig Estey
Nov 22 '18 at 23:28
1
False dichotomy, you compare pointer typedef with not using typedef at all... I would use a non-pointer typedef.typedef double math_func(int a, double b); math_func add, sub; /* ... */ math_func *math_op = add;
. Later on you recommendnode_p
with the comment "one has to look in the .h file for the definition". However if you just usednode_t *
then nothing needs to be looked up
– M.M
Nov 22 '18 at 23:46
1
1
Pointer typedefs are not preferred (by me anyway)
– M.M
Nov 22 '18 at 21:32
Pointer typedefs are not preferred (by me anyway)
– M.M
Nov 22 '18 at 21:32
@M.M Granted, this is a bit of personal style/preference. I've added an update to my answer (too long for a comment) that lays out how I use pointer typedefs and why. See what you think ...
– Craig Estey
Nov 22 '18 at 23:28
@M.M Granted, this is a bit of personal style/preference. I've added an update to my answer (too long for a comment) that lays out how I use pointer typedefs and why. See what you think ...
– Craig Estey
Nov 22 '18 at 23:28
1
1
False dichotomy, you compare pointer typedef with not using typedef at all... I would use a non-pointer typedef.
typedef double math_func(int a, double b); math_func add, sub; /* ... */ math_func *math_op = add;
. Later on you recommend node_p
with the comment "one has to look in the .h file for the definition". However if you just used node_t *
then nothing needs to be looked up– M.M
Nov 22 '18 at 23:46
False dichotomy, you compare pointer typedef with not using typedef at all... I would use a non-pointer typedef.
typedef double math_func(int a, double b); math_func add, sub; /* ... */ math_func *math_op = add;
. Later on you recommend node_p
with the comment "one has to look in the .h file for the definition". However if you just used node_t *
then nothing needs to be looked up– M.M
Nov 22 '18 at 23:46
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437993%2fcorrect-value-type-for-function-pointers-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
It doesn't matter, but I would suggest being consistent throughout your code with the method you do choose to go with, not mix and match
– M.M
Nov 22 '18 at 21:22
!Nishant Note: posted code lacks a declaration of
math_op
and a 1st case assignment. Suggest adding these your post for clarity.– chux
Nov 23 '18 at 3:07