Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function pointer cast on function with inherited C structure

I'm looking for answer if presented in a example function cast and call is valid in C(if not any example how to get similiar behavior would be nice).

Example:

#include <stdio.h>
#include <stdint.h>

typedef struct {
    uint32_t a;
} parent_t;

typedef struct {
    parent_t parent;
    uint32_t b;
} child_t;


typedef void (*funct_ptr_t)(parent_t* pParent, uint32_t x);

void test_function(child_t* pChild, uint32_t x);

int main()
{ 
    funct_ptr_t func = (funct_ptr_t)test_function;
    funct(NULL, 0U);

    return 0;
}

void test_function(child_t* pChild, uint32_t x) {
    // do something
}

@EDIT As above turned to be invalid, i would like to also ask about second approach

typedef void (*funct_ptr_t)(void* pChild, uint32_t x);

void test_function(child_t* pChild, uint32_t x);

int main()
{ 
    funct_ptr_t func = (funct_ptr_t)test_function;
    child_t child;
    func(&child, 0U);

    return 0;
}

void test_function(child_t* pChild, uint32_t x) {
    // do something
}
like image 737
akimata Avatar asked Oct 27 '22 09:10

akimata


1 Answers

This is not valid.

A function can only be called though a compatible function pointer type. For two function pointer types to be compatible, the corresponding arguments must have compatible types and the return types must be compatible.

test_function has type void (*)(child_t*, uint32_t ) but is being called through a function pointer with type void (*)(parent_t*, uint32_t ). This means the function is being called through an incompatible type and doing so triggers undefined behavior.

If you're trying to accept a pointer to different types for the first parameter, the simplest way to handle this is to change the type of the first parameter for both the function and function pointer to void *, then perform the necessary conversion inside of the function.

Another option is to change the type of the first parameter to test_function to parent_t * and perform a cast inside the function. This will work because a pointer to a struct can be converted to a pointer to its first member, so you could do this:

void test_function(parent_t* pChild, uint32_t x);

int main()
{ 
    funct_ptr_t func = (funct_ptr_t)test_function;
    child_t c;
    funct((parent_t *)&c, 0U);

    return 0;
}

void test_function(parent_t* p, uint32_t x) {
    child_t *p_Child = (p_Child *)p;
    // do something
}
like image 151
dbush Avatar answered Nov 15 '22 11:11

dbush