Reputation:
I came across this following code snippet and I have two questions want to ask for help:
//This is the function poiner
int (*OnDataAvail)( int *, int *, int * )
//This is the function header
int ReqHandler_pack(int *vc ATTRIBUTE((unused)),
int *req, int *complete ATTRIBUTE((unused)), void* stream)
if((*request)->dev.OnDataAvail == ReqHandler_pack) {
First: There was a compiler warning for this part of code: warning: comparison of distinct pointer types lacks a cast [enabled by default]
Then I change it to
if((int *)(*request)->dev.OnDataAvail == (int *)ReqHandler_pack)
By changing this, the warning was not there. But, I am not sure why it works.
Another question is: does Function pointer needs to have the same number of arguments?
Upvotes: 1
Views: 192
Reputation: 1
Yes, two function pointers need to have compatible signatures (for the pointed function) to be compared (or assigned). This means same arity (number of arguments) and compatible types of argument of each rank and same result type.
A given implementation may have an ABI specifying different calling conventions (for functions of different signatures).
The fact that two function pointers are bitwise equal is implementation dependent (of course the address of some routine foo
is equal to the address of the same routine foo
, and two different functions of the same signature compare unequal).
This is to permit implementations having, at the machine level, different ways or instructions to call some C function, depending on its signature. For instance, passing arguments by registers or on the machine stack, and using different jump or call machine instructions or having different banks or spaces for code, etc... However, I don't know any such weird implementations...
Upvotes: 2
Reputation: 45654
It works by happenstance.
Specifically, because your implementation says that all pointer types (code, data (void, struct, ...)) are round-trip cast-compatible (using either before casting back to the proper type is something else again). All modern desktops do so (x86 at least in flat-memory mode), though only some microcontroller.
What you want to do for well-defined behavior is cast those function-pointers to the same function pointer type (all function pointer types are round-trip cast-compatible).
Even then though, it is not guaranteed that any two function pointers compare unequal.
6.3.2.3 Pointers
1 A pointer to
void
may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer tovoid
and back again; the result shall compare equal to the original pointer.
2 For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal.
3 An integer constant expression with the value 0, or such an expression cast to typevoid*
, is called a null pointer constant. The macroNULL
is defined in<stddef.h>
(and other headers) as a null pointer constant; see 7.19. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
4 Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation. The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.
6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
7 A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned In general, the concept ‘‘correctly aligned’’ is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C. for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
8 A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
Emphasis added by me to mark the relevant parts.
Upvotes: 1