Что означает typedef с круглыми скобками типа «typedef int (f) (void)»? Это прототип функции? - PullRequest
27 голосов
/ 09 сентября 2010
typedef int (fc_name) (void);

Здесь fc_name - любой действительный символ C.

Насколько это отличается от указателя функции typedef?

Ответы [ 6 ]

34 голосов
/ 09 сентября 2010

Это typedef для типа функции. Намерение состоит в том, чтобы использовать его для указателей на функции, но в этом случае синтаксис для его использования будет:

int bar(void);

fc_name* foo = bar; /* Note the * */

Обновление: Как упоминалось в комментариях к ответу Джонатана Леффлера , typedef можно использовать для объявления функций. Одним из применений может быть объявление набора функций обратного вызова:

typedef int (callback)(int, void*);

callback onFoo;
callback onBar;
callback onBaz;
callback onQux;
17 голосов
/ 09 сентября 2010

Первые круглые скобки излишни - это эквивалентно:

typedef int fc_name(void);

Я не думаю, что это делает что-то полезное, хотя я не могу заставить GCC жаловаться на это самостоятельно.

Это означает, что fc_name является псевдонимом для типа функции, который не принимает аргументов и возвращает int.Это не так уж и полезно, хотя вы можете объявить, например, функцию rand(), используя:

fc_name rand;

Вы не можете использовать typedef в определении функции.

Указатель на функцию typedef будет выглядеть следующим образом:

typedef int (*fc_name)(void);

Этот код показывает, что typedef без звездочки не являются указателями на функции (обращаясь к удаленному альтернативному ответу):

static int function(void)
{
    return 0;
}

typedef int   fc_name1 (void);
typedef int  (fc_name2)(void);
typedef int (*fc_name3)(void);

fc_name1 x = function;
fc_name2 y = function;
fc_name3 z = function;

При компиляции 'gcc' говорит:

gcc -Wextra -Wall -pedantic -c -O x.c
x.c:10:1: error: function ‘x’ is initialized like a variable
x.c:11:1: error: function ‘y’ is initialized like a variable

И этот код демонстрирует, что вы действительно можете использовать fc_name *var = funcname;, как предложено jamesdlin :

static int function(void)
{
    return 0;
}

typedef int   fc_name1 (void);
typedef int  (fc_name2)(void);
typedef int (*fc_name3)(void);

fc_name1  x_0 = function;
fc_name1 *x_1 = function;
fc_name2  y_0 = function;    // Damn Bessel functions - and no <math.h>
fc_name2 *y_1 = function;    // Damn Bessel functions - and no <math.h>
fc_name3  z   = function;

Используя y0, y1 генерирует предупреждения GCC:

x.c:12:11: warning: conflicting types for built-in function ‘y0’
x.c:13:11: warning: built-in function ‘y1’ declared as non-function

И, основываясь на комментарии от schot :

static int function(void)
{
    return 0;
}

typedef int   fc_name1 (void);
typedef int  (fc_name2)(void);
typedef int (*fc_name3)(void);

fc_name1  x_0 = function;   // Error
fc_name1 *x_1 = function;   // x_1 is a pointer to function
fc_name1  x_2;              // Declare int x_2(void);
fc_name1 *x_3 = x_2;        // Declare x_3 initialized with x_2

fc_name2  y_0 = function;   // Damn Bessel functions - and no <math.h>
fc_name2 *y_1 = function;   // Damn Bessel functions - and no <math.h>
fc_name1  y_2;              // Declare int y_2(void);
fc_name1 *y_3 = x_2;        // Declare y_3 initialized with y_2

fc_name3  z   = function;

Интересно- темные углы Си действительно мрачны.

1 голос
/ 25 ноября 2016

Я никогда прежде не видел, чтобы это было сделано с именем определения типа , но круглые скобки вокруг имени функции полезны для предотвращения ее расширения в виде функционального макроса одно и то же имя Например, функции isxxx в ctype.h определяются как функции и макросы. Это так, что вы можете взять указатель на isalpha. Но как библиотека C определяет вне строки isalpha? Вероятно, так:

#include <ctype.h>

int
(isalpha)(int c)
{
    return isalpha(c);
}

Использование isalpha в теле функции расширено как макрос, использование в заголовке функции - нет.

1 голос
/ 04 апреля 2013

Интересно! Объявление typedef - это объявление с typedef в качестве класса хранения.

typedef int   fc_name1 (void);   
// this defines a function type called fc_name1 
// which takes no parameter and returns int

позже вы можете определить функцию следующим образом:

fc_name1 myFunc;
// this is equivalent to the next line
// int myFunc(void);

Вы должны быть в состоянии понять это из стандарта c / c ++!

0 голосов
/ 29 мая 2011

Правильная форма:

typedef int (*myfunc)(void);

Вы можете определить функцию следующим образом:

int helloword(void) {
    printf("hello, world\n");
}

и затем определить переменную, указывающую на эту функцию:

myfunc hw_func;
hw_func = helloworld;

и вызов функции по указателю функции:

int ret = (*hw_func)();

Причина, по которой нам нужен указатель на функцию, заключается в том, что в языке C нет предопределенного указателя на функцию и использование указателя void * для вызова функции недопустимо в языке C.

0 голосов
/ 09 сентября 2010
  1 #include <stdio.h>
  2 
  3 
  4 typedef int (fc_name)(void);
  5 
  6 
  7 
  8 int test_func1 ()
  9 {
 10     printf("\n test_func1 called\n");
 11 
 12     return 0;
 13 }
 14 
 15 int test_func2 (void)
 16 {
 17     printf("\n test_func2 called\n");
 18     return 0;
 19 }
 20 
 21 int handler_func(fc_name *fptr)
 22 {
 23     //Call the actual function
 24     fptr();
 25 }
 26 
 27 int main(void)
 28 {
 29     fc_name  *f1, *f2;
 30 
 31     f1 = test_func1;
 32     f2 = test_func2;
 33 
 34     handler_func(f1);
 35     handler_func(f2);
 36 
 37     printf("\n test complete\n");
 38 
 39     return 0;
 40 }

ВЫВОД: -

 test_func1 called

 test_func2 called

 test complete

Итак, typedef, о котором я спрашивал (строка 4 здесь), представляет собой Тип функции и не совпадает с указателем функции typedef. Этот тип typedef не имеет большого значения. Они используются как стандарт стиля или просто намеренно создавать запутывание ;-)

...