Вы спрашиваете, допустимо ли приводить указатель на функцию к другому указателю на функцию. Разрешается приводить указатель на функцию к любому другому указателю на функцию. Но вызов функции через такой указатель вызывает неопределенное поведение. C11 6.5.2.2p9
6.5.2.2 Функциональные вызовы
[...]
Если функция определена с типом, который не совместим с типом (выражения), на который указывает выражение, обозначающее вызываемую функцию, поведение не определено.
Другая проблема состоит в том, что ваш код не имеет cast . Он имеет принудительное присваивание:
void *(*fn_ptr)(void) = foo;
Это недопустимо из-за нарушения ограничения, которое должен диагностировать компилятор Си. Приведение будет читать
void *(*fn_ptr)(void) = (void *(*)(void))foo;
Теперь вопрос в том, каково поведение
void *(*fn_ptr)(void) = (void *(*)(void))foo;
void *raw = fn_ptr();
int data = *(int *)raw;
Поведение конструкции не определено в соответствии со стандартом. Конечно, ваша реализация может дать смысл выражению. Вы должны проверить руководства вашего компилятора для поведения в этом случае.
Существовали архитектуры, в которых представление для void *
и int *
не было бы совместимым.
Есливы просто меняете указатель на функцию, возвращающую int *
или приводите обратно перед вызовом, поведение четко определено - неявное преобразование в void *
и явное приведение к int *
в порядке.
Т.е.
int *(*fn_ptr)(void) = foo;
void *raw = fn_ptr();
int data = *(int *)raw;
или
void *(*fn_ptr)(void) = (void *(*)(void))foo;
void *raw = ((int *(*)(void))fn_ptr)();
int data = *(int *)raw;
Или пусть функция вернет void *
:
void *foo(void) {
int *data = malloc(sizeof(int));
*data = 42;
return data;
}
void *(*fn_ptr)(void) = foo;
void *raw = fn_ptr();
int data = *(int *)raw;