2010-07-16 2 views
2

Можно создать дубликат:
What is the point of function pointers?какие указатели на функции

может кто-нибудь объяснить, что указатели на функции и зачем они нужны в неспециалист условия. В c контексте, пожалуйста?

+5

Я бы посоветовал вам посоветоваться с вашей книгой C; если у вас его нет, я бы рекомендовал получить одну из вводных книг, перечисленных в [The Definitive C Book Guide and List] (http://stackoverflow.com/questions/562303/the-definitive-c-book-guide- и-лист). –

+2

dup: http://stackoverflow.com/questions/3229349/function-pointer/3229465#3229465 – eruciform

+2

@eruciform Это немного хромает, ссылаясь непосредственно на ваш собственный ответ в вопросе, который сам был закрыт как дубликат –

ответ

2

Под капотом функция - это просто место в двоичном коде компьютера вашей программы. Когда вы используете функции в C, компилятор создает инструкции, которые переходят в это конкретное место после передачи аргументов функции.

Указатель функций - это переменная, которую вы можете использовать для хранения местоположения функции. Это позволяет одной части вашего кода определять, какая функция используется в другой части вашего кода. Например, функция qsort принимает указатель на функцию, который вы используете для определения порядка сортируемых объектов.

+0

, поэтому вы не знаете, какой fuction вызывать во время выполнения, и вы делаете некоторый тип сравнения и вызываете соответствующую функцию. я прав? – begsor12

+0

Я думаю, что у вас есть суть этого. Например, с помощью qsort вы можете выбрать либо восходящий, либо убывающий порядок на основе ввода пользователем. – Cogwheel

0

Указатель функций аналогичен любому другому указателю, за исключением того, что он указывает на функцию (код).

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

+0

, поэтому вы не знаете, какую функцию вызывать во время выполнения, и выполняете ли вы какое-то сравнение, и вызываете соответствующую функцию. я прав? – begsor12

0

Посмотрите here - на этот вопрос ответили хорошо в другой теме.

0

Указатели функций указывают на двоичный код кода для определенной функции.

Единственный раз, когда я когда-либо использовал их, был с pthreads. Когда вы запускаете поток, вам нужно сказать ему, с чего начать выполнение, поэтому вы должны указать ему указатель на функцию, в которой он должен начинать выполнение. По сути, эта функция становится «main()» для потока, и как только он возвращается из этой функции, поток умирает.

Без указателей функций вы не можете сказать pthreads, где начать выполнение для нового потока.

1

Указатели - это адреса памяти.

Функция указателя адрес в памяти, где начинается код для функции.

Часто во время компиляции вы знаете, какую функцию вы хотите назвать, поэтому ссылаетесь на нее по имени. Когда код si компилируется, компилятор заменяет это имя (обычно относительным) адресом фактического машинного кода.

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

switch(c) { 
    case '+' : add(op1, op2); break; 
    case '*' : multiple(op1, op2); break; 
    case '/' : divide(op1, op2); break; 
} 

но это утомительно и подвержено ошибкам.

Или вы можете написать библиотечную функцию, например qsort, которая знает, как сортировать любой тип, но для выполнения сортировки требуется функция компаратора. Так что нам не нужно открывать и перекомпилировать qsort, qsort позволяет нам передать код - то есть функцию - которую мы хотим использовать для сравнения нашего пользовательского типа.

Таким образом, C (и C++) позволяют адресовать адрес этого кода - адрес функции - который необходимо принять. Взяв адрес, вы получите значение типа указателя на функцию (фактически, указателя типа на функцию типа, где тип функции подписи - то есть тип и номер ее параметров - и ее типа возвращаемого, тип объекта, он возвращается. (Обратите внимание, что подписи не включает типа возвращаемого значения, а тип функции включает как подписи и тип возвращаемого значения.)

Во всяком случае, это дало Конечно, значение может быть присвоено переменной совместимого типа - указателю на функцию и передано или скопировано как любая другая переменная, так как в конце концов это всего лишь нуль mber, адрес в памяти.

Поэтому, учитывая, что у нас есть функция Foo, с обратным типом Int и подпись Const ничтожной *, сопзЬ пустота *:

int foo(const void* lhs, const void* rhs); 

мы можем создать переменную этого типа:

int (*foopointer) (const void*, const void*) ; 

Да, действительно, это объявление переменной! Прочитайте, что как «foopointer - это указатель на функцию, принимающую два указателя константы void и возвращающих int», путем чтения имени («foopointer»), затем слева от указателя («*»), затем справа для parens (" const void *, const void *) ", затем обратно оставил int, который он возвращает. Первый набор парнеров необходим, чтобы это не объявляло функцию, которая возвращает указатель на объект.

Тогда мы можем присвоить адрес нашей функции Foo нашу переменную foopointer, используя адрес-оператор («&»):

foopointer = &foo; 

Фактически адрес-оператор не является строго необходимым, и подразумевается, если мы его не используем, но используем его, чтобы было ясно, что вы принимаете адрес. Это помогает читателям.

Тогда мы можем использовать foopointer, скажем, назвать QSort:

int some_array_of_int[] = { 1, 3, 2) ; 
    qsort(some_array_of_int, 
     3 /* elements */, 
     sizeof(int) /*each element is how big?*/, 
     foopointer) ; 

Конечно, мы могли бы просто использовать Foo непосредственно: QSort (some_array_of_int, 3/* элементы * /, SizeOf (INT)/каждый элемент такой большой? /, foo);

В любом случае, qsort будет использовать foo, чтобы сравнить цифры в массиве, чтобы отсортировать их. (Функция компаратора должна возвращать определенные значения, чтобы это произошло, что выходит за рамки этого обсуждения, но в целом * lhs - * rhs).

Теперь мы не указали, как foo всяких вещи, но мы не должны, чтобы обратного как это сортирует, чтобы сделать это, мы можем просто вернуть отрицание возвращаемого значения Foo в:

int reverse_foo(const void* lhs, const void* rhs) { 
    return - foo(lhs, rhs) ; 
} 

Теперь мы можем решить, во время выполнения, следует ли сортировать или список по возрастанию или по убыванию:

bool reverse = get_reverse_from_user_or_somthing(); 

    qsort(some_array_of_int, 
     3 /* elements */, 
     sizeof(int) /*each element is how big?*/, 
     reverse ? reverse_foo : foo) ; 

Кто писал QSort не имел ни малейшего представления о том, как вы бы написать fooreverse_foo), и вы должны были (возможно) нет возможности перекомпилировать qsort, чтобы сообщить об этом foo (или reverse_foo). Но благодаря указателям на функции, qsort может звонить foo, несмотря на то, что две функции записываются годами друг от друга, разными кодами.

+0

спасибо, что сэр. – begsor12