Show / Hide Table of Contents

MSDN.WhiteKnight - Stack Overflow answers

Ответ на "Несовместимость dll, lib и a между компиляторами"

Answer 880893

Link

Несовместимость бинарных модулей (далее, для краткости, просто "модулей"), произведенных разными компиляторами, определяется в основном следующими тремя аспектами:

  1. Разные правила декорирования имен экспортируемых символов

  2. Разное устройство объектов стандартной библиотеки

  3. Разные правила расположения полей структур в памяти

Первый пункт характерен фактически только для С++: в Си существует набор характерных для конкретной аппаратной платформы соглашений о вызове (например, stdcall, fastcall и cdecl для x86), которые довольно четко прописывают правила декорирования имен. Второй пункт относится и к Си и к С++, но в Си не очень много "объектов стандартной библиотеки" - в голову приходит только FILE*, и экспортировать его через границы модулей нет никакого смысла.

Таким образом да, действительно можно сказать, что С++ "хуже" чем Си в плане бинарной совместимости. Это разумеется не значит, что не нужно на нем писать, это лишь значит, что на границе модулей нужно использовать интерфейс в стиле Си (либо использовать стандартизированный объектно-ориентированный интерфейс, например Component Object Model в Windows).

Есть ли способы делать двоичные библиотеки максимально совместимыми? Чтобы написанная однажды библиотека dll могла быть подключена в самых разных языках без боли и страданий?

Использование DLL на С/С++ в других языках это больше чем вопрос бинарного интерфейса (например, в них может просто не быть концепции заголовочных файлов, указателей и т.п.), но обычно да, библиотека с интерфейсом в стиле Си может быть использована и из других языков с тем или иным количеством дополнительных телодвижений.

Рекомендации для обеспечения максимальной бинарной совместимости:

  • Экспортируйте через границы бинарного модуля только простые функции с припиской extern "C" (т.е, никаких классов, шаблонов, перегруженных функций, пространств имен и т.п.)

  • Передавайте через границы модулей только простые типы, указатели на них и указатели на функции.

  • Если все же передаете структуры, сделайте первым членом структуры ее размер. Это позволит, если вы натолкнетесь на различия по выравниванию полей, обнаружить несоответствие в общем размере структуры и хотя бы нормально вернуть ошибку.

  • Не передавайте через границы модулей объекты стандартной библиотеки, например указатели FILE*.

  • Блоки динамической памяти должны освобождаться всегда в том же модуле, в котором были выделены. Т.е., если библиотека возвращает программе-клиенту указатель на блок памяти, выделенный malloc внутри себя, она должна предоставлять специальную функцию для его освобождения (вызывающую внутри себя free), вместо того, чтобы полагаться на вызов free в программе-клиенте.


Content is retrieved from StackExchange API.

Auto-generated by ruso-archive tools.

Back to top Stack Overflow answers (published from sources in GitHub repository). Copyright (c) 2020, MSDN.WhiteKnight. Content licensed under BSD 3-Clause License.
Generated by DocFX