що насправді означає __declspec (dllimport)?


91

Я бачив вихідний код Qt таким:

class Q_CORE_EXPORT QBasicAtomicInt
{
public:
...
};

Який Q_CORE_EXPORTмакрос визначає, як показано нижче:

define Q_DECL_IMPORT __declspec(dllimport)

То що __declspec(dllimport)насправді означає?


Відповіді:


118

__declspec є специфічним атрибутом Microsoft, який дозволяє вказати інформацію про клас зберігання.
(Nitpicker's Corner: Однак низка інших постачальників компіляторів - наприклад, GCC - тепер підтримує це мовне розширення для сумісності з встановленою базою коду, написаного для компіляторів Microsoft. Деякі навіть надають додаткові атрибути класу сховища.)

Двома з тих атрибутів класу сховища, які можна вказати, є dllimportта dllexport. Вони вказують компілятору, що функція або об'єкт імпортується або експортується (відповідно) з DLL.

Більш конкретно, вони визначають інтерфейс DLL для клієнта, не вимагаючи визначення модуля (.DEF файлу ). Більшості людей набагато простіше використовувати ці розширення мови, ніж створювати файли DEF.

Зі зрозумілих причин __declspec(dllimport)і, __declspec(dllexport)як правило, поєднуються між собою. Ви використовуєте dllexportдля позначення символу як експортованого з DLL, і використовуєтеdllimport для експортування цього експортованого символу в інший файл.

Через це, і оскільки один і той же заголовочний файл зазвичай використовується як під час компіляції DLL, так і в клієнтському коді, який використовує інтерфейс DLL, загальним шаблоном є визначення макросу, який автоматично перетворюється на відповідний специфікатор атрибутів під час компіляції. Наприклад:

#if COMPILING_DLL
    #define DLLEXPORT __declspec(dllexport)
#else
    #define DLLEXPORT __declspec(dllimport)
#endif

А потім позначення всіх символів, які слід експортувати DLLEXPORT.

Імовірно, саме це робить Q_CORE_EXPORTмакрос, вирішуючи або Q_DECL_IMPORTабо Q_DECL_EXPORT.


__declspec не є належним чином "специфічним для MS" (набагато більше "для компілятора), і деякі компілятори також використовують цю декларацію для декількох платформ. Деякі значення атрибутів є (dllexport / dllimports специфічні для MS, насправді, оскільки DLL є MS лексикон)
Еміліо Гаравалья

9
@Emilio: Наскільки мені відомо, Microsoft винайшла __declspecпозначення як розширення мови С ++. Я вважаю, що GCC зараз це підтримує, але це в першу чергу з міркувань сумісності з компіляторами Microsoft. І я не розумію, чим "MS-specific" відрізняється від "specific-compiler". Корпорація Майкрософт написала компілятор C ++, і багато людей використовують її. Він поставляється з Visual Studio.
Коді Грей

8
Microsoft робить компілятор. Він називається "Компілятор оптимізації Microsoft C / C ++", cl.exe. Багато людей помилково посилаються на Visual Studio, ніби це компілятор, але це IDE. Я не знаю, чому люди роздумують про те, що означає "специфічне для Microsoft". Це не означає "середовище MS" (яким би воно не було), і це, безумовно, не означає "Windows". Так, інші постачальники компіляторів тепер підтримують розширення для сумісності з встановленою базою написаного коду, націленого на компілятори Microsoft. Як я вже говорив раніше, наскільки мені відомо, Microsoft винайшла синтаксис. Ось тут ідеться про це.
Коді Грей

2
@CodyGray: Майкрософт, винайшовши його самостійно, буде недостатньо. Однак Microsoft винайшла його, жоден стандарт не містить, інші застосовують його лише для сумісності, і він використовується в першу чергу (якщо не виключно) для програм, орієнтованих на Microsoft Windows разом, робить дуже сильний момент, називаючи його "специфічним для Microsoft"
celtschk

6
Це чудова відповідь, особливо частина про "тому, що один і той же файл заголовка зазвичай використовується як при компіляції DLL, так і в коді клієнта"! Робить кожен аспект імпорту / експорту кришталево чітким.
Ela782,

30

__declspec(dllimport) це специфікатор класу сховища, який повідомляє компілятору, що функція або об'єкт або тип даних визначені у зовнішній бібліотеці DLL.

Функція або об'єкт або тип даних експортуються з DLL із відповідним __declspec(dllexport).


6
Гаразд. Нарешті, після 2 годин читання, я знайшов найбільш ситне, найкоротше, точніше і точніше те, що я хочу.
el psy Congroo

1

__declspec(dllexport)повідомляє компілятору повідомити лінкера про те, що ці символи потрібно розмістити в таблиці експорту (при компілюванні .dll). Під час компіляції програми, яка зв'язується з .dll, __declspec(dllimport)повідомляє компілятору, щоб він створив абсолютний абсолютний регістр-непрямий непрямий виклик (який компонувальник заповнить з роздільною здатністю, щоб вказати на таблицю імпорту), а не звичайний ріп-відносний регістр-прямийінструкція непрямого виклику до невизначеної функції (яка, оскільки не може змінити інструкцію, компоновщик вставляє відносну адресу транка, а потім створює транк, всередині якого розміщує відносний абсолютний регістр-непрямий непрямий виклик до покажчик функції в таблиці імпорту). Це оптимізація розміру та швидкості коду. Саме бібліотека імпорту .lib повідомляє компоновщику, які символи будуть імпортовані, і використовується як керівництво для створення таблиці імпорту та створення необхідних хитрощів у сегменті .text.

https://docs.microsoft.com/en-us/cpp/build/importing-function-calls-using-declspec-dllimport?view=vs-2019 https://docs.microsoft.com/en-us/cpp / build / importing-data-using-declspec-dllimport? view = vs-2019 https://stackoverflow.com/a/4490536/7194773


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.