Top.Mail.Ru
Ответы
Аватар пользователя
7лет
Изменено
Аватар пользователя
Аватар пользователя
Аватар пользователя
Программирование
+3

Динамическая библиотека С++

1) В общем хз как с ней вообще работать... совершенно отсутствует логика... с явным подключением все гораздо проще... Я не понимаю почему Я должен импортировать еще не начиная экспортировать... Ведь по сути сначало должен быть экспорт а уже потом импорт?
2) Также я не понимаю смысла закомментированного мною блока препроцессора вверху, зачем он нужен, если всегда определяется только импорт. Ну и конечно фатальных ошибок, если его убрать вообще, у меня не возникает...
3) Не понятен спецификатор extern. Вроде как без него можно передавать абсолютно любые вещи кроме переменных. Но смысл делать получается перенные глобальными, если мы поидее их экспортируем а не делаем видимыми)))
4) Вот довольно таки часто у работающих программ во время компиляции возникает подобная чушь и затем исчезает и на ее место встает ряд ненайденных библиотек))) смотрите скрин 2, не понятно что еще за несовместимая компоновка... вроде все совместимо...

Если не сложно можете каждый пункт прокоментировать...

По дате
По рейтингу
Аватар пользователя
Новичок
7лет

1. Импорт и экспорт это две совершенно разные секции данных, под секциями я имею ввиду виртуальную\ые страницу\ы в которую линковщик зашивает всю информацию, полученную от компилятора. По сути макрос выше немного искажен, для лучшего понимания сделаю так.
#ifdef THIS_IS_DLL
#define LIBA_API extern "C" __declspec(dllexport)
#else
#define LIBA_API extern "C" __declspec(dllimport)
#endif
Если препроцессор (который как вы знаете начинает работать до компилятора), увидит запись THIS_IS_DLL он определит макрос LIBA_API с __declspec(dllexport), иначе __declspec(dllimport), про extern опишу ниже. __declspec(dllexport) это макрос указание компилятору, Чувак, создай мне таблицу экспорта, я создаю dll - мне нужно, чтобы мои функции\переменные использовали другие процессы! Если вы создаете exe и хотите импортировать функции\переменные, то вы не должны определять THIS_IS_DLL и тогда компилятор создаст таблицу импорта, то есть ссылки на внешние переменные\функции, которые прописаны в dll. После этого макроса обязательно идет декларатор, то есть, а что мы хотим импортировать\экспортировать примерно вида такого - для экспорта
LIBA_API int Sum(int a, int b)
{
return a + b;
}
для импорта реализация не нужна, ибо реализация\определение находится в dll.
2.Вроде разжевал в первом пункте.
3. Перед тем как объясню extern - сначало раскажу, что такое символ в низкоуровневом программировании ассемблера (то есть С++ будет транслировать код именно в ассемблерный). Символ это по сути метка (примерный аналог прыжок на метку через goto) после которого следуют данные или код. Когда мы пишем extern мы создаем символьную ссылку на внешнюю переменную\функцию, то есть переменную\функцию, которая определена в другом месте, это создано для того, чтобы компилятор смог скомпилировать код - например, находящийся в test.cpp, когда внешняя переменная находится например в test2.cpp. extern "C" это указание компилятору что символ не будет декорироваться, то есть так как мы написали LIBA_API int Sum(int a, int b) - имя символа будет совпадать с Sum, если бы мы указали просто extern то имя символа было бы декорированным, то есть перед Sum он подставил какую-нибудь абракадабру, это сделано специально, чтобы С++ мог различать различные полиморфные или шаблонные реализации функций\методов.
4. С этим у всех новичков проблемы, потому как нужно понимать что множественное определение символов запрещено в С\С++, и все символы должны стать известными перед линковкой.

Аватар пользователя
Просветленный
7лет

обычно экспортируют функции, (вроде ещё классы, но я не делал, ибо, нужна работа именно в стиле языка СИ). О переменных я не слышал.
константу можно сунуть в .h файл
если таки нужно получить из dll то можно сделать так

type getVal(){ return val; }

препроцессор, как раньше писал, чтоб разные программы понимали, экспортировать символы или импортировать.
Он должен быть написан в общих .h файлах.

например делаем какой либо движок. Создаём общие include файлы, которые потом пользователи будут подключать, создавая свои программы.
И движок читает эти файлы, и программы тоже читают эти файлы. Но, движок экспортирует функции, а программы импортируют.

когда даёшь свою dll для разработки, то нужно давать и .h файлы со всем необходимом.

extern используется в этом случае (по моему опыту, как я делаю), только для того чтобы дать компилятору понять, что функция экспортируется в отличном от C++ формате
extern "C"{ //такой способ чтобы постоянно не писать extern "C"
__declspec(dllexport) size_t getC(){ return C; }
}

в таком случае имя функции сохранится как есть, без украшательств C++ (декорирование)

тогда можно загружать эту функцию в любом другом языке который способен грузить функции из dll