7.9.6. Указатели на функции, объявленные как extern "C"
7.9.6. Указатели на функции, объявленные как extern "C"
Можно объявлять указатели на функции, написанные на других языках программирования. Это делается с помощью директивы связывания. Например, указатель pf ссылается на С-функцию:
extern "C" void (*pf)(int);
Через pf вызывается функция, написанная на языке С.
extern "C" void exit(int);
// pf ссылается на C-функцию exit()
extern "C" void (*pf)(int) = exit;
int main() {
// ...
// вызов С-функции, а именно exit()
(*pf)(99);
}
Вспомним, что присваивание и инициализация указателя на функцию возможны лишь тогда, когда тип в левой части оператора присваивания в точности соответствует типу в правой его части. Следовательно, указатель на С-функцию не может адресовать функцию С++ (и инициализация его таким адресом не допускается), и наоборот. Подобная попытка вызывает ошибку компиляции:
void (*pfl)(int);
extern "C" void (*pf2)(int);
int main() {
pfl = pf2; // ошибка: pfl и pf2 имеют разные типы
// ...
}
Отметим, что в некоторых реализациях С++ характеристики указателей на функции С и С++ одинаковы. Отдельные компиляторы могут допустить подобное присваивание, рассматривая это как расширение языка.
Если директива связывания применяется к объявлению, она затрагивает все функции, участвующие в данном объявлении.
В следующем примере параметр pfParm также служит указателем на С-функцию. Директива связывания применяется к объявлению функции, к которой этот параметр относится:
// pfParm - указатель на С-функцию
extern "C" void f1( void(*pfParm)(int) );
Следовательно, f1() является С-функцией с одним параметром – указателем на С-функцию. Значит, передаваемый ей аргумент должен быть либо такой же функцией, либо указателем на нее, поскольку считается, что указатели на функции, написанные на разных языках, имеют разные типы. (Снова заметим, что в тех реализациях С++, где указатели на функции С и С++ имеют одинаковые характеристики, компилятор может поддерживать расширение языка, позволяющее не различать эти два типа указателей.)
Коль скоро директива связывания относится ко всем функциям в объявлении, то как же объявить функцию С++, имеющую в качестве параметра указатель на С-функцию? С помощью директивы typedef. Например:
// FC представляет собой тип:
// С-функция с параметром типа int, не возвращающая никакого значения
extern "C" typedef void FC( int );
// f2() - C++ функция с параметром -
// указателем на С-функцию
void f2( FC *pfParm );
Упражнение 7.21
В разделе 7.5 приводится определение функции factorial(). Напишите объявление указателя на нее. Вызовите функцию через этот указатель для вычисления факториала 11.
Упражнение 7.22
Каковы типы следующих объявлений:
(a) int (*mpf)(vectorint);
(b) void (*apf[20])(doub1e);
(c) void (*(*papf)[2])(int);
Как сделать эти объявления более понятными, используя директивы typedef?
Упражнение 7.23
Вот функции из библиотеки С, определенные в заголовочном файле cmath:
double abs(double);
double sin(double);
double cos(double);
double sqrt(double);
Как бы вы объявили массив указателей на С-функции и инициализировали его этими четырьмя функциями? Напишите main(), которая вызывает sqrt() с аргументом 97.9 через элемент массива.
Упражнение 7.24
Вернемся к примеру sort(). Напишите определение функции
int sizeCompare( const string , const string );
Если передаваемые в качестве параметров строки имеют одинаковую длину, то sizeCompare() возвращает 0; если первая строка короче второй, то отрицательное число, а если длиннее, то положительное. Напоминаем, что длина строки возвращается операцией size() класса string. Измените main() для вызова sort(), передав в качестве третьего аргумента указатель на sizeCompare().
Назад Вперед
2013-03-11 13:45:40 Людмила
Спасибо за сайт! Но в разделе 7.1 Вы пишите: "Вызов функции может обрабатываться двумя разными способами. Если она объявлена встроенной (inline), то компилятор подставляет в точку вызова ее тело. Во всех остальных случаях происходит нормальный вызов, который приводит к передаче управления ей, а активный в этот момент процесс на время приостанавливается." Я считаю, что следует написать "а вызывающая функция приостанавливается на время выполнения вызванной функции". Ведь вызывающая и вызываемая функции работают в ОДНОМ (!) процессе. Это относится даже к вызову системных функций, ведь как известно, они (функции ОС) отображаются на виртуальное адресное пространство пользовательского процесса...
2013-02-12 20:09:33 Алексей
Машенька, ввиду того, что вы девушка понять технические наука для вас намного тяжелее, чем парням. А этот материал явно не один из самых легких для освоения, поэтому не отчаивайтесь.
2013-01-18 06:01:36 Машенька
НАПИШИТЕ ДЛЯ ЛЮДЕЙ БЛИН!!!!!!ЧЕСТНОЕ СЛОВО ЗАДОЛБАЛИ!!!!!
2012-08-28 14:18:12 Илья
Спасибо но возникли некоторые вопросы. Вот один из них: Что такой за случай использования фукнции, которая не видна в месте ее вызова? (7.6: "Встроенная функция должна быть видна компилятору в месте вызова...")
2012-02-16 18:13:20 Сергей
Спасибо мне очень помог ваш сайт!
2012-01-19 22:06:14 Artem
Потрясающе. Доступно и понятно. Очень хороший материал.