Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 19, средняя оценка - 4.79
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
#1

Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) - C++

07.02.2014, 17:22. Просмотров 2694. Ответов 46
Метки нет (Все метки)

Не, реально, зачем он?

...Друзья! Много где в инете вы найдёте как кропать dll-ки, например тут. обратите внимание на командную строку:

Bash
1
gcc -c -DBUILD_DLL dllfct.c
Да, так вот. Много где приводят примеры с использованием этго параметра, но зачем он никто толком не знает.

А вот я не поленился и скомандовал --help для каждого из экзешников лежащих в папке mingw\bin- ни для одного из экзешников такого параметра нет. То есть он просто-напросто ни одним из экзешников не используется. Вот результаты, кому интересно, в архиве.

Так зачем же нужен параметр -DBUILD_DLL? Спасибо, кто откликнется.
Вложения
Тип файла: rar rez.rar (46.3 Кб, 9 просмотров)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nick Alte
Эксперт С++
1608 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,931
Завершенные тесты: 1
11.02.2014, 21:36     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #16
Это библиотека импорта: та статическая библиотека, которая генерируется вместе с DLL. Она содержит в себе функции, совпадающие по именам с функциями DLL, которые просто перебрасывают вызовы в DLL. Она же содержит код, который при загрузке приложения загружает DLL и читает оттуда адреса всех функций, а при завершении приложения выгружает DLL.
Всё это можно проделывать и вручную, без implib, но с ней, понятное дело, удобнее.
DrOffset
7060 / 4201 / 949
Регистрация: 30.01.2014
Сообщений: 6,968
16.02.2014, 15:05     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #17
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от kravam Посмотреть сообщение
Второй абзац, честно говоря, не понял. Нельзя ли какой-нибудь маленький примерчик ПОЛЕЗНОГО применения __declspec(dllimport)?
Тут подробно написано.

Цитата Сообщение от kravam Посмотреть сообщение
а потом вернуться к ключу BUILD_DLL.
Да BUILD_DLL не ключ, а макрос. -D - это ключ. Вот пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifdef LIBNAME_USING_WIN32
#   ifdef LIBNAME_USING_CXX_GCC
#       define LIBNAME_EXPORT_DIRECTIVE __attribute__ ((__dllexport__))
#       define LIBNAME_IMPORT_DIRECTIVE __attribute__ ((__dllimport__))
#   elif defined(LIBNAME_USING_CXX_MSVC)
#       define LIBNAME_EXPORT_DIRECTIVE __declspec(dllexport)
#       define LIBNAME_IMPORT_DIRECTIVE __declspec(dllimport)
#   endif
#else
#   ifdef LIBNAME_USING_GCC4
#       define LIBNAME_EXPORT_DIRECTIVE __attribute__ ((visibility("default")))
#       define LIBNAME_IMPORT_DIRECTIVE __attribute__ ((visibility("default")))
#   elif defined(LIBNAME_USING_CXX_GCC)
#       define LIBNAME_EXPORT_DIRECTIVE
#       define LIBNAME_IMPORT_DIRECTIVE
#   endif
#endif
 
#ifdef LIBNAME_BUILD_DLL
#   define LIBNAME_API  LIBNAME_EXPORT_DIRECTIVE
#else
#   define LIBNAME_API  LIBNAME_IMPORT_DIRECTIVE
#endif
Определяя его, мы включаем экспорт функций помеченных LIBNAME_API (где LIBNAME - имя нашей библиотеки). В случае же когда приложение начинает использовать заголовочные файлы нашей библиотеки - этот макрос не определяется и используется по умолчанию импорт.
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
17.02.2014, 20:40  [ТС]     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #18
На счёт __declspec(dllimport)- небольшой тык скыть эксперимент с отладчиком, показал, что всё так.

Не по теме:

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

То есть в

1) связке экзешник + системная dll-ка модификатор __declspec(dllimport) должен отсутсвовать. Где же он есть? Ну, наверное, в

2)связке экзешник+ dll-ка, поставляемая вместе с ним. ТО есть написан экзешник, к нему паровозом идут dll-ка(и), предполагается что эта связка неизменна, поэтому неизменен и адрес функции, вызываемой из этого экзешника, не фиг зря тратить загрузчицкое время на правку адреса.

Это всё понятно. Но мы-то говорим об __declspec(dllimport) в исходинке dll-ки! Получается связка такая:

3) dll-ка с __declspec(dllimport)+ dll-ка (источник функции)

Ну я таких конструкций навороченных с двумя dll-ками не писал ещё, ну ладно, всё это вполне может быть.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=


А теперь, когда мы так успешно выяснили, зачем всё это нужно по отдельности, возвращаемся к нашему вопросу- на фига такой вот монстр?

C++
1
2
3
4
5
6
7
#ifdef BUILD_DLL
   // the dll exports
   #define EXPORT __declspec(dllexport)
#else
   // the exe imports
   #define EXPORT __declspec(dllimport)
#endif
Мне ситуация видится просто: пишем dll-ку, в ней сколько-то импортируемых функций из других dll-ок, сколоько-то экспортируемых и сколько-то ни тех ни других, для внутреннего, тык скыть, потребления. Так вот, прототип каждой из импортируемых функций мы объявляем так:

C++
1
2
3
4
extern "C" __declspec(dllimport) void functsia_imp_0 ();
extern "C" __declspec(dllimport) void functsia_imp_1 ();
extern "C" __declspec(dllimport) void functsia_imp_2 ();
...
А экспортируемые пишем так:
C++
1
2
3
4
extern "C" __declspec(dllexport) void functsia_exp_0 () {};
extern "C" __declspec(dllexport) void functsia_exp_1 () {};
extern "C" __declspec(dllexport) void functsia_exp_2 () {};
extern "C" __declspec(dllexport) void functsia_exp_3 () {};
Или даже так, если уж нам неймётся с макросами:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
////...
 
extern "C" IMPORT void functsia_imp_0 ();
extern "C" IMPORT void functsia_imp_1 ();
extern "C" IMPORT void functsia_imp_2 ();
 
//...
extern "C" EXPORT void functsia_exp_0 () {};
extern "C" EXPORT void functsia_exp_1 () {};
extern "C" EXPORT void functsia_exp_2 () {};
extern "C" EXPORT void functsia_exp_3 () {};
Но где тут может быть полезен вышеприведённый блок макроопределений? Ума не приложу. Уславливаемся, что в DLL-ке у нас определены, например 4 экмпортируемые функции и используются 3 импортируемые. (наверное, последний абзац последнего ответа был как раз про это, но уж больно он громоздкий, извините.)
DrOffset
7060 / 4201 / 949
Регистрация: 30.01.2014
Сообщений: 6,968
17.02.2014, 23:57     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #19
Цитата Сообщение от kravam Посмотреть сообщение
А теперь, когда мы так успешно выяснили, зачем всё это нужно по отдельности, возвращаемся к нашему вопросу- на фига такой вот монстр?
Ссылочку на мсдн мою смотрел?
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
18.02.2014, 10:17  [ТС]     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #20
DrOffset, опять вы думаете обо мне плохо. Там именно то и написано, зачем нужен модификатор
C++
1
__declspec(dllimport)
Но зачем нужно вот это вот:
C++
1
2
3
4
5
6
7
#ifdef BUILD_DLL
   // the dll exports
   #define EXPORT __declspec(dllexport)
#else
   // the exe imports
   #define EXPORT __declspec(dllimport)
#endif
там об этом ни слова.
DrOffset
7060 / 4201 / 949
Регистрация: 30.01.2014
Сообщений: 6,968
18.02.2014, 14:12     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #21
Цитата Сообщение от kravam Посмотреть сообщение
DrOffset, опять вы думаете обо мне плохо. Там именно то и написано, зачем нужен модификатор
C++
1
__declspec(dllimport)
Но зачем нужно вот это вот:
C++
1
2
3
4
5
6
7
#ifdef BUILD_DLL
   // the dll exports
   #define EXPORT __declspec(dllexport)
#else
   // the exe imports
   #define EXPORT __declspec(dllimport)
#endif
там об этом ни слова.
Ну раз зачем нужен __declspec(dllimport) понятно, то ответ зачем нужна конструкция выше, уже не раз сюда постили. Первый ответ в теме ну и мой ответ, например.

Ну, могу еще раз.
Ситуация:
Я разработчик библиотеки (dll). Я собираю свою библиотеку из исходников и указываю макрос -DBUILD_DLL в мэйкфайле.
Конструкция выше срабатывает и проставляет всем функциям __declspec(dllexport), перед которыми стоял EXPORT (на самом деле EXPORT некорректный пример и только запутывает. Лучше использовать нотацию из моего примера. Или посмотреть на WIN32 API (например в файле winbase.h функции помечены как WINBASEAPI). Простановка __declspec(dllexport) помечает функции как экспортируемые. Смотрим MSDN:
Declaring functions as dllexport eliminates the need for a module-definition (.def) file, at least with respect to the specification of exported functions.
То есть это нужно, чтобы была возможность вызывать функции через границу модуля.

Ситуация 2:
Теперь я пользователь библиотеки. Я подключаю заголовочный файл вышеозначенной библиотеки, естественно никакой -DBUILD_DLL я не указываю в своем мэйкфайле. Автоматически начинает применяться вариант__declspec(dllimport). Зачем он нужен, ты уже понял.

ЗЫ. В линуксе, например, можно обходиться без всего этого. Там правила игры немного другие. Но есть похожие по форме приемы (в моем примере как раз один из вариантов). Подробнее тут.
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
18.02.2014, 17:24  [ТС]     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #22
Цитата Сообщение от DrOffset Посмотреть сообщение
Первый ответ в теме
нет, первый ответ был не про то. Первый ответ был про то, почему хорошо определять BUILD_DLL командой компилятору, а явно
C++
1
#define BUILD_DLL 1
-тоже хорошо, но уже не совсем. Вот про что был первый ответ.

+++++++++++++++++++++++++++++++++++++++==

Цитата Сообщение от DrOffset Посмотреть сообщение
Я разработчик библиотеки (dll). Я собираю свою библиотеку из исходников и указываю макрос -DBUILD_DLL в мэйкфайле.
Конструкция выше срабатывает и проставляет всем функциям __declspec(dllexport), перед которыми стоял EXPORT
Я же выше писал- ну зачем эти сложности? Ну написать перед каждой экспортируемой функцией EXPORT и ВСЁ, и не надо никаких ключей. А перед каждой импортируемой IMPORT и опять всё. Я же по условию сам пишу dll и сам определяю, какая пойдёт на экспорт, а какую я буду импортировать!
DrOffset
7060 / 4201 / 949
Регистрация: 30.01.2014
Сообщений: 6,968
18.02.2014, 17:34     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #23
Цитата Сообщение от kravam Посмотреть сообщение
Я же выше писал- ну зачем эти сложности? Ну написать перед каждой экспортируемой функцией EXPORT и ВСЁ, и не надо никаких ключей. А перед каждой импортируемой IMPORT и опять всё.
Именно это и делается, только препроцессором и на автомате. Все соответствующие функции для пользователя библиотеки будут помечены как import. Все функции, которые разработчик пометил будут export. Заголовочный файл один, а импортировать или экспортировать через него будут функции переключается одни флажком.

Цитата Сообщение от kravam Посмотреть сообщение
Я же по условию сам пишу dll и сам определяю, какая пойдёт на экспорт, а какую я буду импортировать!
Ну да. И что? Нужно смотреть на библиотеку с двух сторон, с точки зрения пользователя и с точки зрения ее разработчика. Иначе при твоем подходе нужно будет иметь две версии заголовочного файла, один для экспорта, нужный при сборке либы, а другой для импорта, нужный при использовании либы. Это - сложнее.
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
18.02.2014, 18:36  [ТС]     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #24
Ничё не понял. Может, перейдём к конкретике? Я вот тут подумал- где может быть реальна полезна штука из первого поста. И написал такой код (хотя мне потом скажут, что примеры приводили, никто примеров полезности не приводил. Первый пример действительной полезности ниже)

C++
1
2
3
4
5
6
7
8
9
10
11
//A.cpp
#ifdef BUILD_DLL
   // the dll exports
   #define EXPORT __declspec(dllexport)
#else
   // the exe imports
   #define EXPORT __declspec(dllimport)
#endif
 
extern "C" EXPORT void functsia_0 () {}
extern "C" EXPORT void functsia_1 () {}
Bash
1
2
del A.dll libAdll.a
gcc -shared -o A.dll -Wl,--out-implib,libAdll.a A.cpp -D BUILD_DLL=1
Так, ну а потом я передумал и переписал всё это дело так:

C++
1
2
3
4
//A.cpp
#define EXPORT __declspec(dllexport)
extern "C" EXPORT void functsia_0 () {}
extern "C" EXPORT void functsia_1 () {}
Bash
1
2
del A.dll libAdll.a
gcc -shared -o A.dll -Wl,--out-implib,libAdll.a A.cpp
Даже я не знаю, что и добавить. Два кода. Второй проще причём лишь тем. что убрано лишнее, то есть ничё не добавилось, то есть ничё запоминать не надо, память головную (в смысле помнить, что чем заменить) загружать не надо. Файлы на выходе абсолютно одинаковые.

Так с каким пор стало правильным усложнять себе жизнь?
DrOffset
7060 / 4201 / 949
Регистрация: 30.01.2014
Сообщений: 6,968
18.02.2014, 19:14     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #25
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от kravam Посмотреть сообщение
Так с каким пор стало правильным усложнять себе жизнь?
Ох... Неверно полагать, что все вокруг идиоты.

А теперь к конкретике.
Заголовочный файл где? Как использовать твою dll? Она же не сферическая в вакууме?
Не надо эту конструкцию писать в cpp, ей там действительно не место.
Эту конструкцию пишут в заголовочном файле, вместе с прототипом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//A.h
#ifdef BUILD_DLL
   // the dll exports
   #define DLL_API __declspec(dllexport)
#else
   // the exe imports
   #define DLL_API __declspec(dllimport)
#endif
 
// вызывающего для С++ кода 
#ifdef __cplusplus 
extern "C" {
#endif
 
DLL_API void function_0 ();
DLL_API void function_1 ();
 
#ifdef __cplusplus 
}
#endif
Теперь код самой dll:
C++
1
2
3
4
5
6
7
8
9
10
11
12
//A.c
#include <A.h>
 
void function_0 ()
{
   // реализация
}
 
void function_1 ()
{
   // реализация 
}
Собираем библиотеку:
gcc -shared -o A.dll -Wl,--out-implib,libAdll.a A.с -DBUILD_DLL
Все. Я как разработчик библиотеки свою миссию выполнил.
Теперь я пользователь библиотеки.
Мой код:
C++
1
2
3
4
5
6
7
8
9
//main.cpp
#include <A.h> // тут они уже будут __declspec(dllimport)
 
int main()
{
    function_0();
    // ....
    return 0;
}
Собираем (заметь, никакого -DBUILD_DLL):
gcc main.cpp -lAdll -o myprog
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
18.02.2014, 20:11  [ТС]     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #26
А, ну вот, теперь вроде всё понятно. Оказывается, хидер работает на два фронта. Разработчик dll написал её и дал пользователю вместе с хидером и *.a. Пользователь, не думая о прототипах функций, подключает хидер и, не определяя BUILD_DLL вызывает функции (f()) и те оказываются import. Всё круто. Очень удобно для пользователя.

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

C++
1
#define DLL_API __declspec(dllimport)
(ну или программно находить адрес и вызывать через адрес)

Ну что ж теперь всё ясно. Большое спасибо, огромный пласт тык скыть знаний раскрыт. Если что, спрошу здесь.
DrOffset
7060 / 4201 / 949
Регистрация: 30.01.2014
Сообщений: 6,968
18.02.2014, 20:42     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #27
Цитата Сообщение от kravam Посмотреть сообщение
А, ну вот, теперь вроде всё понятно. Оказывается, хидер работает на два фронта. Разработчик dll написал её и дал пользователю вместе с хидером и *.a. Пользователь, не думая о прототипах функций, подключает хидер и, не определяя BUILD_DLL вызывает функции (f()) и те оказываются import. Всё круто. Очень удобно для пользователя.
Наконец-то Все-таки все тоже самое, что в последнем сообщении было написано в первом.
Вот смотри, я выделю все ключевые слова:
Цитата Сообщение от Nick Alte Посмотреть сообщение
Потому что ленивые программисты используют один и тот же заголовок и для построения самой DLL, где содержащиеся в ней функции описаны как экспортируемые (со спецификатором __declspec(dllexport) в случае Visual Studio), и для использующих ту DLL программ, где их описывают уже как импортируемые, с модификатором __declspec(dllimport). Переключение как раз осуществляется проверкой макроса BUILD_DLL. Менять исходный код, добавляя-убирая этот макрос в зависимости от того, что мы собираем, неудобно. А удобно привязывать этот макрос к проекту, добавляя его в параметры компилятора, а лучше в свойства проекта в IDE, откуда он всё равно попадёт в командную строку.
Разве нет?

Цитата Сообщение от kravam Посмотреть сообщение
Небольшая тык скыть, догадка- получается, если мы имеем скомпилированные таким образом экзешники (к примеру, я пользуюсь билиотекой X.dll, невесть где взятой, и с её помощью что-то пишу), то если вдруг я заимею другую X.dll, то экзешники надо будет перекомпилировать, ибо, вызыванные в них функции вызываются по жёстко прописанным адресам, т. к.
C++
1
#define DLL_API __declspec(dllimport)
Не так. Таблица импорта заполняется фактическими адресами при старте программы. При компиляции она только создается и заполняется "ссылками" на импортируемые функции. А вот таблица экспорта фиксирована.
Вот тут все очень подробно.
Рекомендую еще раз прочитать ссылку на мсдн. Для полноты картины.
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
18.02.2014, 21:57  [ТС]     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #28
Цитата Сообщение от DrOffset Посмотреть сообщение
Наконец-то Все-таки все тоже самое, что в последнем сообщении было написано в первом.
Соглашусь, но разве не для того форум и существует, чтобы чисто и честно, по-товарищески объяснить? Это вообще философский вопрос. Всё написано в книгах/учебниках. И всё написано правильно. А вот поди ж ты- откуда берутся двоечники (лентяев не берём в расчёт)? Есть такой феномен как непонимание, и никуда от него не деться

Цитата Сообщение от DrOffset Посмотреть сообщение
Не так. Таблица импорта заполняется фактическими адресами при старте программы.
Действительно, заполняется. И этот адрес используется при вызове функции, то есть у меня в отладчике так:

Assembler
1
2
mov eax, [адрес в таблице импорта, по которому лежит адрес функции]
call eax
Вот моё заблуждение. Я думал, что будет так:
Assembler
1
2
mov eax, [чётко прописанный адрес]
call eax

Не по теме:

...Откуда взялся "чётко прописанный адрес"? Ну, когда мы компильнули экзешник с модификатором __declspec(dllimport), вот компилятор его и прописал тогда чётко по месту, что называется. Но теперь, я вижу, это не так.

Соответсвующее поле сначала занято RVA имени функции, а при загрузке в память загрузчик прописывает туда её адрес, прямо как по цитатному:
заполняется загрузчиком перед запуском программы и до заполнения адресами функций содержит RVA имен этих функций в таблице просмотра импорта.
К слову, я это примерно знал, поизучав "От зелёного к красному."

Не по теме:


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



+++++++++++++++++++++++++++++++++++++++++++++

Тут вопросов нет. Вопрос возникает совершено не там, откуда ждали. Смотрите. Если мы компилим функцию с модификатором __declspec(dllimport), загрузчик во время загрузки ищет адрес этой функции и его использует. А если компилим БЕЗ __declspec(dllimport), загрузчик... делает то же самое, только использует адрес по-другому. Но по большому счёту, вся-то и сложность и разница в поведении по-разному скомпиленных экзешников должна заключаться в том, КОГДА В ЭКЗЕШНИКЕ СТАНЕТ ИЗВЕСТЕН АДРЕС ФУНКЦИИ

И если адрес функции в ОБОИХ СЛУЧАЯХ становится известным только при загрузке программы в память, тогда мы В ОБОИХ случаях ("с" и "без" __declspec(dllimport)) можем использовать более эффективный код, а именно:

Assembler
1
2
mov eax, [адрес в таблице импорта, по которому лежит адрес функции]
call eax
А на самом деле компилятор без __declspec(dllimport) генерит такой код: добавляет лишний прыжок

Assembler
1
2
call 0x4000000
4000000: jmp DWORD PTR __imp_func1 //вот этот лишний прыжок
Когда мог превосходно сгенерить код, который я написал выше. Я так понимаю, он эффективнее прыжка, и это же написано в msdn.
DrOffset
7060 / 4201 / 949
Регистрация: 30.01.2014
Сообщений: 6,968
18.02.2014, 22:19     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #29
Цитата Сообщение от kravam Посмотреть сообщение
А на самом деле компилятор без __declspec(dllimport) генерит такой код: добавляет лишний прыжок

Assembler
1
2
call 0x4000000
4000000: jmp DWORD PTR __imp_func1 //вот этот лишний прыжок
Когда мог превосходно сгенерить код, который я написал выше. Я так понимаю, он эффективнее прыжка, и это же написано в msdn.
Функция без __declspec(dllimport) может находиться как внутри твоей программы, так и в dll. Понять это без подсказки компилятор не способен. Поэтому чтобы разрешить ситуацию он генерит наиболее общий код, который возможно, он подходит и для этого случая и для того. Помечая функцию __declspec(dllimport) мы как бы намекаем ему, что она точно не в нашем модуле, позволяя исключить лишний шаг.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.02.2014, 18:13     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW)
Еще ссылки по теме:
C++ Для чего нужен символ \b?
C++ Для чего нужен break?
Для чего нужен Sizeof C++
C++ DLL не компилирует (использую vector, string, .lib)
C++ Виртуальный деструктор, для чего нужен?

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
kravam
быдлокодер
1693 / 880 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
19.02.2014, 18:13  [ТС]     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW) #30
Честное слово, я не понял мысли. Во-первых, почему компилятор не способен это понять? Откуда такой вывод? Я в отладчике наблюдаю, что очень даже способен. Но это не главное. На этот вопрос, как и на возникающие далее вообще можно не отвечать. Мне кажется, они не имеют отношения к делу.

А вот это имеет. Псведокод:

Вызов функции из dll

Это назовём good_kod
//Используем __declspec(dllimport)
mov eax, адрес_в таблице_импорта
call [eax]
А это назовём bad_kod
//Не используем __declspec(dllimport)
call <прыгаем_на_некоторый_адрес_в_коде>
jmp [адрес_в таблице_импорта]
Так, а теперь что мешает компилятору заменить bad_kod на good_kod? Ничего! Пусть заменяет и раз и навсегда избавимся от ненужного дополнительного промежуточного прыжка. Не заменяет. Почему?
Yandex
Объявления
19.02.2014, 18:13     Создание *.dll: для чего нужен компилятору параметр -DBUILD_DLL? (использую MinGW)
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru