Указатель функции typedef? - PullRequest
412 голосов
/ 28 ноября 2010

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

typedef void (*FunctionFunc)();

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

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

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

Ответы [ 6 ]

425 голосов
/ 28 ноября 2010

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
175 голосов
/ 28 ноября 2010
  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"
    
31 голосов
/ 28 ноября 2010

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

С typedef вместо этого она определяет1007 * как имя для этого типа.

7 голосов
/ 21 сентября 2017

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

using FunctionFunc = std::function<void(int arg1, std::string arg2)>;
1 голос
/ 14 мая 2019

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

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

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

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

long typedef long a;

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

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

1 голос
/ 12 января 2017
#include <stdio.h>
#include <math.h>

/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/

// typedef a primitive data type
typedef double distance;

// typedef struct 
typedef struct{
    int x;
    int y;
} point;

//typedef an array 
typedef point points[100]; 

points ps = {0}; // ps is an array of 100 point 

// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)

// prototype a function     
distance findDistance(point, point);

int main(int argc, char const *argv[])
{
    // delcare a function pointer 
    distanceFun_p func_p;

    // initialize the function pointer with a function address
    func_p = findDistance;

    // initialize two point variables 
    point p1 = {0,0} , p2 = {1,1};

    // call the function through the pointer
    distance d = func_p(p1,p2);

    printf("the distance is %f\n", d );

    return 0;
}

distance findDistance(point p1, point p2)
{
distance xdiff =  p1.x - p2.x;
distance ydiff =  p1.y - p2.y;

return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
}
...