i try to initializing an array of function pointers and i have "warning":
ring-buffer.c:57:19: warning: assignment from incompatible pointer type [enabled by default]
RBufP->rbfunc[0] = &RBufPush;
^
but the neighborhood's ok:
/*typedef for func pointer*/
typedef RBRetCod_t (*RBFunc)();
/*RBufP*/
typedef struct {
RBufSiz_t size; /*size and mask*/
RBufDat_t rbufdat;
RBufPoint_t head, tail;
RBFunc rbfunc[3]; /*announce of function pointers array*/
} RBuf_t;
RBuf_t *RBufP;
...
/*init for func pointers array*/
RBufP->rbfunc[2] = &RBufDel; /*it is ok*/
RBufP->rbfunc[1] = &RBufPull; /*it is ok*/
RBufP->rbfunc[0] = &RBufPush; /*it is bad, why???*/
...
/*body of the functions*/
RBRetCod_t RBufPull(unsigned char *dat)
{
return RBSUCC;
}
RBRetCod_t RBufDel(void)
{
return RBSUCC;
}
RBRetCod_t RBufPush(unsigned char dat)
{
return RBSUCC;
}
please explain to me why the warning occurs in this line: RBufP->rbfunc[0] = &RBufPush;
, but in adjacent rows are not there?
See C11 section 6.7.6.3 §14, specifying when 2 function types shall be considered compatible:
[...] If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. [...]
This is the case for RBufPull
and RBufDel
, but not RBufPush
as unsigned char
gets promoted to int
.
If you called RBuPush
through a pointer of type RBFunc
, an int
argument would get pushed to the stack, whereas RBufPush
would expect an unsigned char
. Depending on calling convention and endianness, you'll get incorrect results.
One solution is to change RBufPush
to take an int
argument. Another one is to use a cast, ie
RBufP->rbfunc[0] = (RBFunc)&RBufPush;
You'll need to cast back to the correct type RBRetCod_t (*)(unsigned char)
before calling rbfunc[0]
.
From ISO/IEC:9899:
J.5.7 Function pointer casts
1 A pointer to an object or to void may be cast to a pointer to a function, allowing data to be invoked as a function (6.5.4).
2 A pointer to a function may be cast to a pointer to an object or to void, allowing a function to be inspected or modified (for example, by a debugger) (6.5.4).
But this rule is limited through:
6.3.2.3 Pointers
[...]
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 pointed-to type, the behavior is undefined.
So you are trying to acces different functions with the same Pointerobject type. This is undefined behavior and the warning therefor is correct.
Note:
What it seems to me, what you try to achieve would be something like an interface in C#
.
But this kind of functionallity is not available in C
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With