Указатель на функцию Typedef?

Я учусь динамически загружать библиотеки DLL, но я не понимаю эту строку

typedef void (*FunctionFunc)();

У меня есть несколько вопросов. Если кто-то сможет им ответить, буду признателен.

  1. Почему используется typedef?
  2. Синтаксис выглядит странно; после void не должно быть имени функции или чего-то такого? Похоже на анонимную функцию.
  3. Создан ли указатель на функцию для хранения адреса памяти функции?

Так что я сейчас в замешательстве; ты можешь мне кое-что прояснить?


person Jack Harvin    schedule 28.11.2010    source источник
comment
Взгляните на ссылку (последний раздел) learncpp.com/cpp-tutorial / 78-указатели-функции   -  person enthusiasticgeek    schedule 03.05.2013
comment
Следует отметить, что, поскольку вместо него можно использовать c ++ 11 using FunctionFunc = void (*)();. Немного яснее, что вы просто объявляете имя для типа (указатель на функцию)   -  person user362515    schedule 08.01.2016
comment
просто чтобы добавить к @ user362515, для меня более ясная форма: using FunctionFunc = void(void);   -  person topspin    schedule 29.05.2016
comment
@topspin IIRC эти два не одно и то же. Один - это тип указателя на функцию, другой - тип функции. Есть неявное преобразование, поэтому оно работает, IANA (C ++) L, так что можно вмешаться и поправить меня. В любом случае, если намерение состоит в том, чтобы определить тип указателя, я думаю, что синтаксис с * немного более явный.   -  person user362515    schedule 31.05.2016


Ответы (6)


typedef - это языковая конструкция, которая связывает имя с типом.
Вы используете ее так же, как и исходный тип, например

  typedef int myinteger;
  typedef char *mystring;
  typedef void (*myfunc)();

используя их как

  myinteger i;   // is equivalent to    int i;
  mystring s;    // is the same as      char *s;
  myfunc f;      // compile equally as  void (*f)();

Как видите, вы можете просто заменить имя typedefed на его определение, приведенное выше.

Сложность заключается в указателе на синтаксис функций и удобочитаемости в C и C ++, а typedef может улучшить читаемость таких объявлений. Однако синтаксис является подходящим, поскольку функции - в отличие от других более простых типов - могут иметь возвращаемое значение и параметры, поэтому иногда длинное и сложное объявление указателя на функцию.

Читаемость может стать очень сложной с указателями на массивы функций и некоторыми другими, даже более косвенными разновидностями.

Чтобы ответить на ваши три вопроса

  • Почему используется typedef? Для облегчения чтения кода - особенно для указателей на функции или имен структур.

  • Синтаксис выглядит странным (в указателе на объявление функции). Этот синтаксис неочевиден для чтения, по крайней мере, в начале. Вместо этого использование объявления typedef облегчает чтение

  • Создан ли указатель функции для хранения адреса памяти функции? Да, указатель функции хранит адрес функции. Это не имеет ничего общего с конструкцией typedef, которая только облегчает запись / чтение программы; компилятор просто расширяет определение typedef перед компиляцией фактического кода.

Пример:

typedef int (*t_somefunc)(int,int);

int product(int u, int v) {
  return u*v;
}

t_somefunc afunc = &product;
...
int x2 = (*afunc)(123, 456); // call product() to calculate 123*456
person Breaking not so bad    schedule 28.11.2010
comment
в последнем примере слово «квадрат» не будет означать одно и то же, т.е. указатель на функцию вместо использования & square. - person pranavk; 05.03.2013
comment
Вопрос, в вашем первом примере typedef у вас есть форма typedef type alias, но с указателями функций кажется, что есть только 2 аргумента, typedef type. По умолчанию для псевдонима используется имя, указанное в аргументе типа? - person dchhetri; 03.05.2013
comment
@pranavk: Да, square и &square (и, действительно, *square и **square) все относятся к одному и тому же указателю на функцию. - person Jonathan Leffler; 03.05.2013
comment
@ user814628: не совсем понятно, о чем вы спрашиваете. С typedef int newname вы превращаете newname в псевдоним для int. С typedef int (*func)(int) вы превращаете func в псевдоним для int (*)(int) - указатель на функцию, принимающую аргумент int и возвращающую значение int. - person Jonathan Leffler; 03.05.2013
comment
Думаю, я просто запутался в заказе. С typedef int (*func)(int) я понимаю, что func - это псевдоним, но немного запутался, потому что псевдоним связан с типом. Переходя к typedef int INT в качестве примера, мне было бы легче, если бы указатель на функцию typedef имел форму typedef int(*function)(int) FUNC_1. Таким образом, я могу видеть тип и псевдоним в двух отдельных токенах вместо того, чтобы быть объединенными в один. - person dchhetri; 03.05.2013
comment
Причина, по которой это выглядит так, заключается в том, что typedef является спецификатором класса хранения, например extern или static. Вы можете подумать об этом, изменив класс хранения на определения типов. источник. Такое понимание упрощает запоминание синтаксиса. - person Dan; 05.12.2013
comment
Относительно Создан ли указатель функции для хранения адреса памяти функции? Да, нет, не в этом коде. Кроме того, неверно указывать, что имя, введенное с помощью typedef, является ключевым словом. А что касается оценки синтаксиса, то создатели языков C и C ++ не согласны с этим, называя это неудачным экспериментом. - person Cheers and hth. - Alf; 24.03.2015
comment
Хотя функция обычно просто распадается на указатель функции, это не всегда так. Безопаснее просто всегда использовать &, чем полагаться на всегда происходящее затухание. (Или вы можете просто подождать, пока компилятор не пожалуется, а затем добавить его - на ваше усмотрение :-)) - person Jon Spencer; 28.03.2017
comment
Было бы неплохо поговорить немного подробнее о семантике указателя на функцию в стиле C и указателя на объектно-ориентированную функцию C ++, в частности о том, сколько больше памяти требуется в C ++, а typedef просто не работает для указателей функций OO. . - person ; 02.05.2018
comment
Обратите внимание, что указатель на функцию не обязательно является просто адресом. Что это на самом деле, зависит от вашей платформы. На некоторых платформах это действительно просто адрес первого байта машинного кода функций, на других платформах это может быть что-то другое. На платформе PPC, например, указатель на функцию фактически был парой адресов: один давал начало машинного кода, другой - связанную с ним таблицу глобальных переменных. Таким образом, 1_. Другие платформы могут использовать что-то еще более странное - указатели на функции - это не то же самое, что обычные указатели! - person cmaster - reinstate monica; 17.05.2019
comment
Кроме того, тест Google пишет typedef как это , очень странно. @ ring-Ø Не могли бы вы кое-что объяснить? - person Lewis Chan; 16.08.2019
comment
как ни странно, вы даже можете сделать typedef returntype smth(), а затем объявить указатель на него как smth* f = &somemethod - person Andi; 25.05.2020

  1. typedef используется для псевдонимов типов; в этом случае вы применяете псевдоним FunctionFunc к void(*)().

  2. Действительно, синтаксис выглядит странно, взгляните на это:

    typedef   void      (*FunctionFunc)  ( );
    //         ^                ^         ^
    //     return type      type name  arguments
    
  3. Нет, это просто сообщает компилятору, что тип FunctionFunc будет указателем на функцию, он не определяет его, например:

    FunctionFunc x;
    void doSomething() { printf("Hello there\n"); }
    x = &doSomething;
    
    x(); //prints "Hello there"
    
person Jacob Relkin    schedule 28.11.2010
comment
typedef не объявляет новый тип. у вас может быть много typedef-определенных имен одного и того же типа, и они не различны (например, из-за перегрузки функций). есть некоторые обстоятельства, при которых в отношении того, как вы можете использовать имя, typedef-определенное имя не совсем эквивалентно тому, как оно определено, но несколько typedef-определенных имен для одного и того же эквивалентны. - person Cheers and hth. - Alf; 28.11.2010
comment
+1 за ответ на вопрос 2 - очень понятно. Остальные ответы тоже были ясны, но этот вопрос мне особенно запомнился :-) - person Michael van der Westhuizen; 19.01.2012

Без слова typedef в C ++ объявление объявляло бы переменную FunctionFunc с указателем типа на функцию без аргументов, возвращающую void.

Вместо typedef он определяет FunctionFunc как имя этого типа.

person Cheers and hth. - Alf    schedule 28.11.2010
comment
Это действительно хороший способ подумать об этом. Если вы внимательно прочитаете другие ответы, они на самом деле не решают путаницу OP по поводу запутанности псевдонима и имени. Прочитав этот пост, я узнал кое-что новое. - person Mad Physicist; 07.04.2015

Если вы можете использовать C ++ 11, вы можете использовать ключевые слова std::function и using.

using FunctionFunc = std::function<void(int arg1, std::string arg2)>;
person Halil Kaskavalci    schedule 21.09.2017
comment
без C ++ 11 ключевое слово using было бы похоже на typedef std::function<void(int, std::string)> FunctionFunc;, на случай, если кому-то понадобится еще одна оболочка для функций без C ++ 11 - person Top-Master; 11.03.2019

Для общего случая синтаксиса вы можете посмотреть приложение A к стандарт ANSI C.

В форме Бэкуса-Наура вы можете видеть, что typedef имеет тип storage-class-specifier.

В типе declaration-specifiers вы можете видеть, что вы можете смешивать множество типов спецификаторов, порядок которых не имеет значения.

Например, правильно сказать:

long typedef long a;

чтобы определить тип a как псевдоним для long long. Итак, чтобы понять typedef для исчерпывающего использования, вам нужно проконсультироваться с некоторой формой backus-naur, которая определяет синтаксис (есть много правильных грамматик для ANSI C, а не только для ISO).

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

person alinsoar    schedule 14.05.2019

person    schedule
comment
При каких обстоятельствах нужен «&»? Например, работают ли func_p = & findDistance и func_p = findDistance одинаково хорошо? - person Donna; 30.10.2017
comment
Имя функции - это указатель, поэтому использовать с ним символ «&» не нужно. Другими словами, '&' является необязательным, когда рассматриваются указатели на функции. Однако для примитивного типа данных вам нужно использовать '&', чтобы получить его адрес. - person Amjad; 30.10.2017
comment
Просто всегда казалось странным, что знак «&» может быть необязательным. Если typedef используется для создания указателя на примитив (например, typedef (*double) p, является ли '&' необязательным? - person Donna; 31.10.2017
comment
Я думаю, вы хотели ввести typedef double* p, чтобы определить указатель на double. Если вы хотите заполнить указатель p из примитивной переменной, вам нужно будет использовать '&'. Примечание: мы вам * ‹имя указателя›, чтобы разыменовать указатель. * используется в указателе функции для разыменования указателя (имени функции) и перехода к блоку памяти, где расположены инструкции функции. - person Amjad; 31.10.2017