Смешанные указатели, массивы и объявления типов функций в C - PullRequest
8 голосов
/ 26 августа 2009

Мой друг пытался проверить меня на C (мой самый сильный язык - C ++), и он задал мне три вопроса, на которые я не смог ответить:

Попробуйте объяснить следующие объявления:

1) int (*x)(int, char *, void *);
2) int (*x[10])(int, char *, void *);
3) int (**x[10])(int, char *, void *);

Может ли кто-нибудь объяснить эти объявления функций и объяснить, какие концепции используются?

Ответы [ 5 ]

31 голосов
/ 26 августа 2009

Вам нужна программа cdecl, которая даст вам точный, правильный ответ на такие вопросы. Обучение интерпретации таких утверждений вручную выполнимо и полезно, но даже в этом случае cdecl чрезвычайно полезен для проверки правильности ответа.

prompt>cdecl
Type `help' or `?' for help
cdecl> explain int (*x)(int, char *, void *);
declare x as pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (*x[10])(int, char *, void *);
declare x as array 10 of pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (**x[10])(int, char *, void *);
declare x as array 10 of pointer to pointer to function (int, pointer to char, pointer to void) returning int
cdecl>
21 голосов
/ 26 августа 2009

Ну, первый - это указатель на функцию. Другими словами, он объявляет переменную «x», которая указывает на функцию следующего типа:

int function(int, char*, void*);

И может использоваться следующим образом:

int myfunc(int a, char* b, void* c) {
    return a;
}

void acallingfunction() {
    int (*x)(int, char*, void*);
    x = myfunc;
    x(1, "hello", 0);
}

Второй, похоже, неверный синтаксис, но я могу ошибаться. Если бы он имел звездочку перед x (например, int (* x [10]) (int, char *, void *)), это был бы массив указателей на функции, и он использовался бы как обычный массив:

x[3](1, "Hi there", 0);

Третий - это массив указателей на указатели на функции, который не кажется практичным, но вполне допустим. Пример использования может быть:

void anothercaller() {
    int (*x)(int, char*, void*);
    int (**y)(int, char*, void*);
    x = myfunc;
    y = &x;
    (*y)(1, "hello", 0);
}

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

Обратите внимание, что все они, по сути, также являются допустимыми C ++. ;)

Редактировать: Я совершил зверства void main (), по-видимому.

Редактировать 2: Как указывает Крис Латс ниже, они действительно должны быть заключены в typedefs. Typedefs делают код, содержащий указатели на функции, НАМНОГО понятнее.

7 голосов
/ 26 августа 2009
  1. Указатель на функцию
  2. Массив указателей на функции
  3. Массив указателей на указатели функций
6 голосов
/ 26 августа 2009

Как указывалось выше, они являются указателями на функции, но написаны довольно неприятно (на мой взгляд). Я бы написал так:

typedef int (*funcptr)(int, char *, void *);

funcptr x;
funcptr x[10];
funcptr *x;

См. Отличный ответ Уолта В. , чтобы узнать больше о функциональных указателях.

3 голосов
/ 27 августа 2009

Поскольку синтаксис C подобен синтаксису C ++ в этом вопросе, geordi может быть вам интересен. Это еще один хороший инструмент для обучения и изучения этих объявлений (и других вещей, связанных с C ++, а иногда и с C).

geordi: << ETYPE_DESC(x); int (*x)(int, char *, void *);
lvalue pointer to a function taking an integer, a pointer to a character, a pointer to anything, and returning an integer

geordi: << ETYPE_DESC(x); int (*x[10])(int, char *, void *);
lvalue array of 10 pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers

geordi: << ETYPE_DESC(x); int (**x[10])(int, char *, void *);
lvalue array of 10 pointers to pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers

Как объясняется на его странице, он может сделать гораздо больше, включая создание типа для вас

geordi: make type array of 10 pointers to functions taking an integer and returning void
void(*[10])(int)

Если вы в принципе знаете, как объявлять вещи, но не уверены в одном, вы можете использовать скобки:

geordi: make type ( void(int, bool) )*
void(*)(int, bool)

Если вы хотите увидеть, как это выглядит с идентификатором в нем, вы также можете изменить тип имен

geordi: -c int x;
Success
geordi: make x a ( void(int, bool) )* and show
-c void (* x)(int, bool) ;

Если вы создаете декларацию, но не уверены в приоритетах операторов, то функции приоритета geordi могут помочь вам

geordi: precedence *x(a, b)
*(x(a, b))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...