2014-09-04 3 views
7

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

float (*func(unsigned id))(float value) { 
    ... 
} 

Я понимаю, что:

  • Это определение функции называется func
  • func принимает один аргумент типа unsigned под названием id
  • func возвращается указатель на функцию, которая выглядит как: float f(float value)

Но я не понимаю, почему возвращаемое значение f (возвращаемая функция указатель) отделяется от списка аргументов.

Также есть: func(unsigned id) выражение, которое оценивает какой-либо указатель? Это причина, почему работает (*func(unsigned id))?

Может кто-нибудь прояснить этот синтаксис шаг за шагом?

+0

Не стоит добавлять в ответ, но 'cdecl' это инструмент командной строки, которая будет объяснить это для вас , – abligh

ответ

7

Выражение func(id) возвращает указатель на функцию, которая принимает float как аргумент и возвращает float.

float(*f)(float v); // pointer to a function 
float val;  

f = func(3);  // returns a pointer to a function 
val = (*f)(3.14); // calls the function pointed to with argument 3.14 

Конечно, можно переписать последнее утверждение:

val = (*func(3))(3.14); // take the ptr returned by func(3) and call the function pointed to. 

Если у вас есть функция, как:

float fct1 (float v) { return 2.0f*v+3.1f; } 

вы могли бы написать:

f = fct1;  // reassign the pointer to function f to the adress of fct1 

Давайте посмотрите на синтаксис. Стандарт C11 (проект N1570) указывает в пункте 6.5.2.2 пункт 1: «Выражение, обозначающее вызываемую функцию) должно иметь указатель на функцию« и в пункте 3, что: ». Постфиксное выражение, за которым следуют скобки() содержащий возможно пустой список выражений, разделенных запятыми, является вызовом функции. "

Это относится, конечно, обычные случаи:

val = fct1 (3.14); // fct1 is the function designator which adresses the function 
val = (*f) (3.14); // (*f) the dereferenced function pointer, so it addresses the function 

Но следующий справедливо и в соответствии со стандартом:

val = f(3.14); // This works as well, because f is a pointer to a function 
val = func(3)(3.14) // works also because func(3) is a pointer to a function 

Однако первое выражение является неоднозначным для человеческого читателя, который может думать f в качестве обозначения функции, ожидая, что он будет определен где-то. И второе необычно. Более того, более ранние версии C не распознавали их. My K & R edition 1978 года потребовал формы (* f)() для вызова указателя функции.

Последнее синтаксическое замечание: если вы определили бы f как float *f (float);, это не было бы понято как указатель на функцию, а как прямое объявление простой функции с именем f и возвращающее указатель на float. Зачем ?Потому что C precedence rules дает () более высокий приоритет, чем *, что означает, что компилятор понимает его как (float *)(f(float)). Вот почему явная скобка требуется, чтобы показать, что (*f) является указателем функции.

3
float (*func(unsigned id))(float value); 

ли декларация функции, которая принимает неподписанных Int как аргумент и возвращает указатель на функцию.

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

float f(float value); 

имя функции func:

float (*func(unsigned id))(float value); 
     ^^^^ 

аргумент функции func:

float (*func(unsigned id))(float value); 
      ^^^^^^^^^^^ 

типа возврата из функция func:

float (*func(unsigned id))(float value); 
    ^^^^^^^^     ^^^^^^^^^^^^^ 

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

float (*func())(float value); 

Вы спросили: Кроме того, есть: func(unsigned id) выражение, которое в какой-то указатель?

Нет, это имя func и аргумент (unsigned id) функции

Вы начинаете видеть, что теперь является func? Это функция, которая возвращает указатель, который указывает на другую объявленную функцию.

Я включил код, в котором вы можете явно увидеть, что является возвращаемым значением функции func по сравнению с ссылкой на функцию f.

#include <stdio.h> 

float f(float value); 
float (*func(unsigned id))(float value); 

int main() 
{ 

    /* print the address of the f function 
    * using the return value of function func 
    */ 
    printf("func return value: %p\n\n", func(2)); 




     /* print the address of the f function referencing 
     * its address 
     */ 
    printf("referencing f address: %p\n", &f); 

    return 0; 
} 

float (*func(unsigned id))(float value) 
{ 
    printf("Original function with argument id = %d called\n", id); 
    return f; 
} 

float f(float value) 
{ 
    printf("f function\n"); 
    return 0.1; 
} 
5

Возьмите этот шаг за шагом с помощью от C gibberish ↔ English

float (*func(unsigned id))(float value) { ... } 

Первый заменить «Func» с «е», как этот отличный веб-сайт имеет проблемы с «Func», а затем удалить параметр имена.

float (*f(unsigned))(float) 
// declare f as function (unsigned) returning pointer to function (float) returning float 

Из этого f является объявлением функции, которая принимает unsigned id. Это часть f(unsigned).

Он возвращает переменную x, как если бы она была объявлена ​​float (*x)(float). Первая половина этого, как наблюдал ОП, отделена от второй половины в первоначальном объявлении функции.

Предлагайте эксперимент с этим сайтом помнить, чтобы не использовать «Func»

Примеры:

int f2(unsigned); 
// declare f2 as function (unsigned) returning int 
int (*f3(unsigned)); 
// declare f3 as function (unsigned) returning pointer to int 
int (*f4)(unsigned); 
// declare f4 as pointer to function (unsigned) returning int 
int (*f5(unsigned))(char); 
// declare f5 as function (unsigned) returning pointer to function (char) returning int 
+0

Очень приятно! Итак, ваш 'f3' - это просто расширенная форма того, как мы все это знаем -' int * f3 (unsigned) '? –

+0

@barak manos Да - то же самое. Добавлен 'f3', так как это поможет объяснить OP' (* func (unsigned id)) '. – chux

+0

Получил. Никогда не приходилось возвращать указатель функции. Наверное, поэтому синтаксис выглядел таким нечитаемым. В любом случае, это кажется бессмысленным. Я не могу думать о каком-либо сценарии, в котором мне понадобится вернуть указатель функции ... Спасибо –