C++: отсутствие стандартизации на двоичном уровне

C++: отсутствие стандартизации на двоичном уровне
C++: отсутствие стандартизации на двоичном уровне - markusspiske @ Unsplash

Почему ISO/ANSI не стандартизировал C++ на двоичном уровне? У С++ много проблем с переносимостью, и только из-за отсутствия стандартизации на двоичном уровне.

Дон Бокс пишет (цитата из его книги Essential COM, глава COM As A Better C++)

C++ и переносимость


Как только будет принято решение о распространять класс C++ как DLL, один сталкивается с одним из основных слабые стороны C++, то есть отсутствие стандартизация на бинарном уровне. Хотя проект ISO/ANSI C++ Рабочий документ пытается систематизировать, какие программы будут компилироваться и что семантические эффекты от их запуска будут быть, он не пытается стандартизировать бинарная модель времени выполнения C++. впервые эта проблема станет очевидно, когда клиент пытается связать против библиотеки импорта DLL FastString из среда разработки C++ другое чем тот, который использовался для создания Библиотека FastString.

Есть ли больше преимуществ или потерь из-за отсутствия двоичной стандартизации?

Языки с бинарно-совместимой скомпилированной формой являются относительно новой фазой[*], например среды выполнения JVM и .NET. Компиляторы C и C++ обычно выдают собственный код.

Преимущество в том, что нет необходимости в JIT, или интерпретаторе байт-кода, или виртуальной машине, или любой другой подобной вещи. Например, вы не можете написать загрузочный код, который запускается при запуске машины, в виде красивого, переносимого байт-кода Java, если, возможно, машина не может выполнять байт-код Java собственными средствами, или у вас есть какой-то конвертер из Java в несовместимый с двоичным кодом родной код. исполняемый код (теоретически: не уверен, что это можно рекомендовать на практике для кода начальной загрузки). Вы можете написать его на C++, более или менее, хотя и не на переносимом C++ даже на уровне исходного кода, так как он будет много возиться с магическими аппаратными адресами.

Недостатком является то, что, конечно, собственный код вообще работает только на той архитектуре, для которой он был скомпилирован, а исполняемые файлы могут быть загружены только загрузчиком, который понимает их исполняемый формат, и только связывается и вызывает другие исполняемые файлы для той же архитектуры и АБИ.

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

Если бы стандарт C++ определил все это, это лишило бы многих свобод, доступных в настоящее время разработчикам. Разработчики пользуются этими свободами, особенно при написании очень низкоуровневого кода на C++ (и C, у которого та же проблема).

Если вы хотите написать что-то, что немного похоже на C++, для бинарно-переносимой цели, есть C++/CLI, предназначенный для .NET, и Mono, чтобы вы могли (надеюсь) запускать .NET где угодно, кроме Windows. Я думаю, что можно убедить компилятор MS создавать чистые сборки CIL, которые будут работать на Mono.

Есть также потенциально вещи, которые можно сделать, например, с помощью LLVM для создания бинарно-переносимой среды C или C++. Однако я не знаю, появился ли какой-либо широко распространенный пример.

Но все они основаны на исправлении многих вещей, которые C++ делает зависимыми от реализации (например, размеры типов). Затем среда, которая понимает переносимые двоичные файлы, должна быть доступна в системе, где должен выполняться код. Разрешая непереносимые двоичные файлы, C и C++ могут перемещаться туда, куда не могут переносимые двоичные файлы, и поэтому стандарт вообще ничего не говорит о двоичных файлах.

Затем на любой данной платформе реализации обычно по-прежнему не обеспечивают двоичную совместимость между различными наборами параметров, хотя стандарт их не останавливает. Если Дону Боксу не нравится, что компиляторы Microsoft могут создавать несовместимые двоичные файлы из одного и того же источника в соответствии с параметрами компилятора, то ему нужно жаловаться на команду компилятора. Язык C++ не запрещает компилятору или ОС зафиксировать все необходимые детали, поэтому, если вы ограничитесь Windows, это не будет фундаментальной проблемой для C++. Microsoft решила этого не делать.

Различия часто проявляются как еще одна вещь, которую вы можете сделать неправильно и привести к сбою вашей программы, но может быть достигнут значительный выигрыш в эффективности, например, между несовместимыми отладочными и выпускными версиями dll.

[*] Я не уверен, когда эта идея была впервые изобретена, возможно, в 1642 году или где-то в этом роде, но их нынешняя популярность относительно нова, по сравнению с тем временем, когда C++ придерживался проектных решений, которые не позволяли определять бинарную переносимость.


LetsCodeIt, 29 мая 2023 г., 21:12