Разрешено ли приводить функцию, возвращающую указатель объекта, к функции, возвращающей указатель void? - PullRequest
4 голосов
/ 24 октября 2019

В этих разделах указано, что вызов указателя функции с несовместимым типом приводит к неопределенному поведению.

C89 3.5.4.3 p9

Для двух функцийтипы должны быть совместимы, оба должны указывать совместимые типы возврата . Кроме того, списки типов параметров, если они присутствуют, должны согласовываться по количеству параметров и при использовании терминатора многоточия;соответствующие параметры должны иметь совместимые типы.

C89 3.5.4.1 p2

Для совместимости двух типов указателей оба должны иметь одинаковую квалификацию и оба должны иметь значение указатели на совместимые типы .

C89 3.3.4 p3

Указатель на функцию одного типа может быть преобразован вуказатель на функцию другого типа и обратно;результат должен сравниваться равным исходному указателю. Если преобразованный указатель используется для вызова функции, тип которой не совместим с типом вызываемой функции, поведение не определено.

Совместимо ли оно с приведением любого другого типа указателя объекта к пустому указателю?

C89 3.3.4 p3

Гарантируется, однако,что указатель на объект данного выравнивания может быть преобразован в указатель на объект того же выравнивания или менее строгого выравнивания и обратно;результат должен сравниваться равным исходному указателю. (Объект с типом символа имеет наименее строгое выравнивание.)

C89 3.1.2.5 p20

Указатель на void должен иметь те же требования к представлению и выравниванию, что иуказатель на тип символа.

C89 3.2.2.3 p1

Указатель на void может быть преобразован в или из указателя на любой неполный или объектный тип. Указатель на любой неполный или тип объекта может быть преобразован в указатель на void и обратно;результат должен сравниться с исходным указателем.

Пример:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int *foo(void) {
    int *data = malloc(sizeof(int));
    *data = 42;
    return data;
}

int main(int argc, char *argv[]) {
    void *(*fn_ptr)(void) = foo;
    void *raw = fn_ptr();
    int data = *(int *)raw;
    printf("%d\n", data);
}

1 Ответ

10 голосов
/ 24 октября 2019

Вы спрашиваете, допустимо ли приводить указатель на функцию к другому указателю на функцию. Разрешается приводить указатель на функцию к любому другому указателю на функцию. Но вызов функции через такой указатель вызывает неопределенное поведение. 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...