В чем разница между void * (*) () и void *? - PullRequest
2 голосов
/ 07 февраля 2020

В одной из моих программ я получаю сообщение об ошибке

invalid conversion from 'void* (*)()' to 'void*' [-fpermissive]

Я пытаюсь понять разницу между этими двумя типами данных. Это очень сбивает с толку.

Что я думаю, что эти типы данных:
void* (*)() Так что этот тип данных является указателем на пустоту (void*), которая также имеет другой указатель ((*) ), и по какой-то странной причине он содержит пустые скобки. Итак, я думаю, что память для этого типа данных выглядит так: |--void address--|--pointer of unknown type--|--something denoting no arguments--|

, тогда есть void*. Это кажется простым и представляет только адрес функции. Модель памяти должна быть такой простой, как |--void address--|.

Почему это так странно, что функция, которая выдает ошибку, выглядит следующим образом.

void callFunction(void *voidThing){
void *testVariable = voidThing;
}

И, насколько мне известно, это создает testVariable типа указателя, и этот указатель на пустоту. Эта функция также принимает параметр указателя типа, и этот указатель также является пустым.

Почему компилятор выдает ошибку, даже если локальная переменная имеет тот же тип параметра? В чем разница между переменными с точки зрения объема памяти этих двух?

1 Ответ

7 голосов
/ 07 февраля 2020

Это типы :

  • void * - указатель на пустоту (может указывать на любой объект, а не на функцию)
  • void * () - функция не принимает аргументов и возвращает void *
  • void * (*) () - указатель на функцию не принимает аргументов и возвращает void *

Пример объявления идентификатора для каждого из приведенного выше, соответственно:

void *object_ptr;    // variable: pointer to object

void *function();    // function  (not a variable)

void * (*function_pointer)();  // variable: pointer to function

Синтаксис для типов функций размещает идентификатор перед списком аргументов, аналогичная вещь происходит с массивами. Это называется инфиксная запись .

Деклараторами указателя являются postfix , т. Е. Идентификатор следует после *.

В void * (*) () необходим первый набор скобок, поскольку void * *() будет другой тип (грамматика объявления приводит к тому, что void * * остается вместе).


Функция callFunction сама по себе корректна, однако сообщение об ошибке, вероятно, появляется при попытке вызвать ее с неверным аргументом, например, адрес функции. void * может содержать только адрес объекта.

Некоторые платформы могут разрешать использование reinterpret_cast для приведения указателя объекта к указателю на функцию или наоборот, эта функция условно поддерживается с определяемой реализацией семантикой , означающей, что реализации могут разрешать или не разрешать ее, но должны документировать поведение, если они это делают.

...