2014-11-09 5 views
1

У меня есть короткая программа, с которой я собираюсь протестировать «бесконечную рекурсию». Тем не менее, я встречаю еще один сложный вопрос, связанный с указателем на функцию ...Тип указателя функции

программа выглядит следующим образом:

#include <stdio.h> 

int repeat(char (*func)(int, int), int a) { 
    func(a, a+1); 
    return repeat(func, a+1); 
} 

char f (int a , int b){ 
    printf("%d\n", a); 
    //return (double)(a + b); 
    return 'c'; 
} 

int main(int argc, char const *argv[]) 
{ 
    repeat(&f, 1); 
    return 0; 
} 

Что касается меня, я думаю, что «F» в «повтора (& F, 1)»имеет тип„полукокса *“и 'FUNC' в„Int повторе (полукокса (* FUNC) (INT, INT), внутр а)“имеет тип„полукокса *“ ,слишком.

Однако, это кажется странным. Если я изменил «(char (* func) (int, int), int a)« to »(char func (int, int), int a)», компилятор (тестирование в gcc и vc6) не давайте никаких предупреждений, и результат выполнения тот же.

Если я изменю «(CHAR (* Func) (Int, Int), внутр а)» к «(двойной FUNC (целое, целое), внутр а)», компилятор бросает:

предупреждение: несовместимые типы указателей прохождения 'символ () (INT, INT)' для параметра типа 'двойной () (Int, Int)' [-Wincompatible-указатель типов] повторения (& F, 1);

Кажется, что компилятор лечить «дважды (целое, целое)» и «двойной (*) (целое, целое)» тот же самый материал. Другими словами, если я меняю «(char (* func) (int, int), int a)« to »double (* func) (int, int)», компилятор выдает одно и то же сообщение (Я тестировал):

предупреждение: типы несовместимыми указатель прохождения 'символ () (INT, INT)' для параметра типа 'двойных () (Int, Int)' [-Wincompatible-указатель типов ] repeat (& f, 1);

God ... Ну, это еще не конец. После этого я меняю «повтор (& f, 1)« «повторить (f, 1)» с другими частями без изменений. То есть, вся программа:

#include <stdio.h> 

int repeat(char (*func)(int, int), int a) { 
    func(a, a+1); 
    return repeat(func, a+1); 
} 

char f (int a , int b){ 
    printf("%d\n", a); 
    //return (double)(a + b); 
    return 'c'; 
} 

int main(int argc, char const *argv[]) 
{ 
    repeat(f, 1); 
    return 0; 
} 

компилятор не дают каких-либо предупреждений и результаты погонных одинаковы.

Таким образом, я смущен тем, что весь следующий париз не дает никаких предупреждений и правильных результатов.

1 repeat(&f, 1) int repeat(char (*func)(int, int), int a) 
    2 repeat(&f, 1) int repeat(char func(int, int), int a) 
    3 repeat(f, 1) int repeat(char (*func)(int, int), int a) 
    4 repeat(f, 1) int repeat(char func(int, int), int a) 

Конечно, 'е' в «повтора (F, 1)» имеет тип «полукокса (Int, Int)», и 'Func' в "Int повторе (double (func) (int, int), int a) "имеет тип" char () (int, int) ".

Вы можете сделать вывод, изменив «Int повтор (символ (* FUNC) (целое, INT), внутр а)» к «INT повтора (двойной (* FUNC) (целое, целое), Int А)»и проверьте предупреждение:

предупреждение: несовместимые типы указателей проходящего 'символа (Int, Int)' для параметра типа 'двойного () (Int, Int)' [-Wincompatible-указатель типов ] repeat (f, 1); *

Кто может комментировать? Я полностью считаю, что только первый из четырех правилен относительно типа.

+3

В этом коде отсутствует 'char *'. 'char (*) (int, int)' является указателем на функцию, возвращающую 'char' и принимающую два аргумента' int'. Также, http://cdecl.org. –

+1

Возможный дубликат [Синтаксис указателя функции C] (http://stackoverflow.com/questions/14114749/c-function-pointer-syntax) –

+0

Обратите внимание, что система типов C не может объявить невариантную функцию, которая принимает себя как параметр функции. –

ответ

1

Тип параметра:

Порядок precendence, введенной () в синтаксисе:

int repeat(char (*func)(int, int), int a) 

означает, что (*func)(int,int) - функция, которая принимает два аргумента int и возвращает char. Значение * означает, что func указатель на функцию, возвращающую char.

Следующая более современный синтаксис работал бы так:

int repeat(char func(int, int), int a) 

ВНИМАНИЕ, следующий вид близок к первому, но будет совершенно другой, аргумент функции будет указатель на функцию, возвращающую char *:

int repeat(char *func(int, int), int a) 

И да, просто для полноты картины, int repeat((char *)func(int, int), int a) будет ошибка синтаксиса, так как (char*) будет пониматься как оператор отлитого в то время как тип, как ожидается.

Использование F и & е синтаксис:.

C11 стандарт раздел 6.5.3.2 гласит, что "Унарный & оператор дает адрес операнда Если операнд имеет тип„“ типа «», то результат имеет тип «» указатель на тип «» «:

  • f быть функция, принимающая два int в качестве аргумента и Ретур ning a char
  • Таким образом, &f является указателем на функцию, принимающую два аргумента int и возвращающий char.

Но стандарт в разделе 6.3.2.1/4 также говорится, что "функция целеуказатель это выражение, которое имеет тип функции. (...) функция целеуказатель с типом„“функция типа возвращения„“является преобразуется в выражение, имеющее тип «» указатель на функцию типа возвращения «» «:

  • f быть функция, принимающая два int в качестве аргумента и возвращает char
  • , если это предусмотрено в выражении (конечно, не в синтаксисе вызов функции), f также понимается как указатель на функцию, принимающую два аргумента int и возвращающий char.

В настоящее время вы найдете оба синтаксиса.

Исторически говоря, в прежние времена использование * в синтаксисе (*func)() является обязательным для вызова функции указал (посмотреть оригинал K & R).

+0

Большое спасибо, это удивительно, что вы знали так много даже о стандарте C/C11. очень круто. Итак, в прошлом они разные, но то же самое в наши дни? – Zirun

+0

Возможно, так развиваются основные языки? Появляются новые синтаксисы, но старые сохраняются из-за огромной базы кода. Тогда это вопрос вкуса: некоторые предпочитают 'extern char rpt (char (*) (int, int));' и some 'extern char rpt (char (int, int));' – Christophe

+0

В основном приятный ответ, но последнее предложение неточно. У меня есть копия K & R 1st Edition, и она содержит указатели на функции на pp114-117. Не одному из имен функций, используемых в качестве указателя на функцию, предшествует символ '&'; в то время это не было законным (но было разрешено C89, еще более десятилетия в будущем, когда книга была написана). Кроме того, в K & R 1 единственным способом вызова указателя на функцию как функции является '(* pointer_to_func) (arg1, arg2)'; опять же, стандарт C разрешил стенографию 'pointer_to_func (arg1, arg2)'. –

3

При использовании в качестве параметра функции, оба синтаксиса

foo(char bar(int, int), int a) 

и

foo(char (*bar)(int, int), int a) 

идентичны с точки зрения компилятора.

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

foo(&f, 1) 
foo(f, 1) 

Что касается меня, я думаю, что f в repeat(&f, 1) имеет тип char * и func в int repeat(char (*func)(int, int), int a) имеет тип char * тоже.

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

+0

Спасибо! Я получил ответ, когда вернулся с рабочего места ... На самом деле, если они будут такими же! (Ответ от Кристофа кажется более полным, поэтому я проголосую за него, у вас уже есть репутация 33.2k:) вы geek.) – Zirun

+0

«f и func оба имеют тип char (*) (int, int), то есть они указатель на функцию, которая принимает два int в качестве аргумента и возвращает char ". Еще раз спасибо. Тип - char (*) (int, int). Я сделал глупую ошибку. – Zirun

Смежные вопросы