Читаем Linux API. Исчерпывающее руководство полностью

В особых случаях можно присвоить libfilename значение NULL. Данное действие заставит функцию dlopen() вернуть дескриптор главной программы (в стандарте SUSv3 это называется глобальным символьным объектом). Если указать этот дескриптор в последующем вызове dlsym(), поиск запрашиваемого символа в первую очередь будет проходить в главной программе, затем в разделяемых библиотеках, загруженных при запуске программы, и только потом в библиотеках, загруженных динамически с помощью флага RTLD_GLOBAL.

42.1.2. Анализ ошибок: dlerror()

При получении ошибки из dlopen() или другой функции, входящей в программный интерфейс dlopen, можно попытаться узнать ее причину, получив указатель на соответствующую строку, используя вызов dlerror().

#include

const char *dlerror(void);

Возвращает указатель на строку с описанием ошибки или NULL, если с момента последнего вызова dlerror() никаких ошибок не было

Функция dlerror() возвращает NULL, если с момента ее последнего вызова не возникало никаких ошибок. В следующем разделе вы увидите, как это может помочь на практике.

42.1.3. Получение адреса символа: dlsym()

Функция dlsym() ищет именованный символ (symbol — функцию или переменную) в библиотеке, на которую указывает дескриптор (handle), и в ее дереве зависимостей.

#include

void *dlsym(void *handle, char *symbol);

Возвращает адрес символа или NULL, если символ не был найден

Если символ найден, dlsym() возвращает его адрес; в противном случае возвращается NULL. В качестве аргумента handle обычно выступает дескриптор библиотеки, возвращенный предыдущим вызовом dlopen(). Но это может быть и один из так называемых псевдодескрипторов, описанных ниже.

У dlsym() есть родственная функция, dlvsym(handle, symbol, version), которая имеет похожее назначение, но может применяться для поиска в библиотеке версионных символов, чьи версии совпадают со значением аргумента version (версионирование символов будет описано в подразделе 42.3.2). Для получния объявления этой функции из заголовочного файла нужно определить макрос проверки возможностей _GNU_SOURCE.

Значение символа, возвращенного функцией dlsym(), может быть равно NULL; тот же результат мы получим, если символ не был найден. Чтобы различать эти два случая, следует заранее вызвать dlerror() (для очистки любых ошибок, которые накопились до сего момента); затем, если повторный вызов dlerror(), сделанный после dlsym(), вернет ненулевое значение, то мы будем знать, что произошла ошибка.

При наличии в аргументе symbol имени переменной можно присвоить результат, возвращенный dlsym(), указателю соответствующего типа и, разыменовав его, извлечь значение этой переменной:

int *ip;

ip = (int *) dlsym(symbol, "myvar");

if (ip!= NULL)

printf("Value is %d\n", *ip);

Если аргумент symbol содержит имя функции, то эту функцию можно вызвать с помощью указателя, полученного в результате вызова dlsym(). Результат выполнения dlsym() можно поместить в указатель подходящего типа, как показано ниже:

int (*funcp)(int); /* Указатель на функцию, принимающую целочисленный

аргумент и возвращающую целочисленный результат */

Однако мы не можем просто присвоить результат выполнения dlsym() такому указателю, как показано ниже:

funcp = dlsym(handle, symbol);

Причина в том, что стандарт C99 запрещает операцию присваивания между указателем на функцию и void *. В качестве решения можно воспользоваться (немного грубым) приведением типов:

*(void **) (&funcp) = dlsym(handle, symbol);

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

res = (*funcp)(somearg);

Вместо синтаксиса вида *(void **), приведенного выше, для присваивания значения, возвращенного функцией dlsym(), можно воспользоваться почти равнозначной альтернативой:

(void *) funcp = dlsym(handle, symbol);

Но если при компиляции задействовать параметр gcc — pedantic, то для этого кода будет выдано предупреждение ANSI C forbids the use of cast expressions as lvalues (Стандарт ANSI C запрещает использование приведения типов в качестве значений lvalue). Выражение *(void **) будет интерпретировано без замечаний, поскольку оно присваивает данные по адресу, на который указывает значение lvalue.

Во многих реализациях UNIX можно избавиться от предупреждений компилятора, применив следующее приведение типов:

funcp = (int (*) (int)) dlsym(handle, symbol);

Однако в первой технической поправке к стандарту SUSv3 (Technical Corrigendum Number 1, TC1), касающейся функции dlsym(), отмечается, что стандарт C99 требует, чтобы для подобных преобразований компиляторы выводили предупреждение, и предлагается использовать вместо этого синтаксис *(void **), описанный выше.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных