Typedef не работает как typedef [type] [new name]
. Часть [new name]
не всегда заканчивается.
Вы должны смотреть на это так: если [some declaration]
объявляет переменную, typedef [same declaration]
определит тип.
E.g.:
int x;
объявляет переменную с именем x типа int -> typedef int x;
определяет тип x как int.
struct { char c; } s;
определяет переменную с именем s некоторого типа структуры -> typedef struct { char c; } s;
определяет тип s как некоторый тип структуры.
int *p;
объявляет переменную с именем p с указателем типа на int -> typedef int *p;
определяет тип p как указатель на int.
А также:
int A[];
объявляет массив целых чисел с именем A -> typedef int A[];
объявляет тип A как массив целых чисел.
int f();
объявляет функцию с именем f -> typedef int f();
объявляет тип функции f как возвращающий int и не принимающий аргументов.
int g(int);
объявляет имя функции g -> typedef int g(int);
объявляет тип функции g как возвращающий int и принимающий один int.
В качестве отступления: обратите внимание, что все аргументы функции идут после нового имени! Поскольку эти типы также могут быть сложными, после [новое имя] может быть много текста. Печально, но факт.
Но это еще не указатели функций, а просто типы функций. Я не уверен, что какой-либо тип функции существует в C или C ++, но он полезен в качестве промежуточного шага в моем объяснении.
Чтобы создать настоящий указатель на функцию, мы должны добавить к имени '*'. Что, к сожалению, имеет неправильный приоритет:
typedef int *pf();
объявляет тип функции pf как возвращающий int *. Ой, это не то, что было задумано.
Поэтому используйте () для группировки:
typedef int (*pf)();
объявляет, что тип указателя на функцию pf возвращает int и не принимает аргументов.
typedef int (&rf)();
объявляет ссылочный тип функции rf как возвращающий int и не принимающий аргументов.
Давайте теперь посмотрим на ваши примеры и ответим на ваши вопросы:
typedef int (&rifii) (int, int);
объявляет ссылочный тип функции rifii как возвращающий int и принимающий два аргумента int.
И очевидно (?) button2[2]( );
вызовет copy();
.
Правильный синтаксис без typedef трудно написать правильно без компилятора и трудно прочитать даже с компилятором:
void (*edit_ops[])() = { &cut, &paste, ©, &search };
void (*file_ops[])() = { &open, &append, & close, &write };
void (**button2)() = edit_ops;
void (**button3)() = file_ops;
button2[2]( );
Вот почему все предпочитают typedefs при использовании указателей на функции.
При чтении найдите место, чтобы начать читать. Читайте как можно правее, но соблюдайте группировку по (). Затем читайте влево как можно больше, опять же ограничиваясь grouping (). Закончив все внутри (), начните читать вправо, затем влево.
Применительно к void (*edit_ops[])()
это означает, что
- edit_ops есть (идите вправо)
- массив (ударьте в конец группы, поверните налево)
- указателя (конец группировки)
- в функцию, принимающую (проанализируйте () справа)
- без аргументов (идите налево)
- возвращение пустоты
Для экспертов. Чтобы еще больше усложнить задачу, аргументы могут иметь имена (которые будут проигнорированы), поэтому может быть даже сложно найти, с чего начать синтаксический анализ! Например. typedef int (*fp)(int x);
допустимо и то же самое, что и typedef int (*fp)(int);
. Имена могут даже иметь () вокруг них: typedef int (*fp)(int (x));
Но, как мы видели, имена аргументов могут быть опущены, поэтому разрешено даже следующее: typedef int (*fp)(int ());
. Это по-прежнему указатель на функцию, принимающий один int и возвращающий int. В случае, если вы хотите, чтобы ваш код был действительно трудным для чтения ...
person
Sjoerd
schedule
02.08.2011