Теперь Кью работает в режиме чтения

Мы сохранили весь контент, но добавить что-то новое уже нельзя

Почему компиляторы высших языков программирования не могут переводить код сразу в ассемблер?

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

Языки программирования+2
C
  ·   · 8,8 K
Программист, преподаватель программирования...  · 17 янв 2021

Для начала, компиляторы и так, как правило, генерируют или ассемблер, или машинный код. Компиляторы языков вроде C++ и Rust генерируют машинный код процессоров, компиляторы Java и C# — код виртуальной машины. Бывают транспиляторы, которые переводят код с одного высокоуровневого языка на другой, например TypeScript в JavaScript, но они нам сейчас не интересны.

Программы из библиотек собираются уже не компиляторами, а компоновщиками («линковщиками», «линкерами»), при этом компоновка может быть как статической, так и динамической. При статической компоновке в исполнимый файл добавляется как код, написанный программистом, так и код библиотек. При динамической исполнимый файл содержит только код, написанный программистом + ссылки на библиотеки с зависимым кодом. В этом случае недостающие библиотеки загружаются операционной системой (или виртуальной машиной) при запуске программы.

Динамическая компоновка позволяет нескольким программам зависеть одновременно от одних и тех же библиотек, что экономит место на диске и оперативную память.

При статической компоновке компоновщик старается включить в целевой файл только те средства библиотек (функции, классы…), которые либо непосредственно упоминаются в коде программиста, либо упоминаются в коде используемых средств.

Библиотеки обычно стараются делать более универсальными, поэтому в них помещают возможности, охватывающие самые разные сценарии использования. И, порой, вырезать что-то одно маленькое получается невозможно — одна функция прямо или косвенно упоминает всю библиотеку.

Попробуйте скопировать одну (произвольную) статью в Википедии в документ Word, а потом скопировать все статьи, на которые из исходной есть ссылка, а потом статьи по ссылкам из скопированных и т.д. Сотня страниц, не меньше выйдет.

А попытаться исключить всё не нужное, что реально не используется в программе, во-первых, очень сложно, а во-вторых, невозможно.

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

if (источник данных == диск)
  открыть файл и прочитать
else if (источник данных == сеть)
  подключиться к серверу и попросить данные
else
  сообщить «Не указан источник данных»

Вторая ветка программы предполагает зависимость от ещё одной библиотеки, библиотеки подпрограмм работы с сетью

И, допустим, программа, использующая эту библиотеку, всегда предполагает, что данные всегда находятся на диске (переменная «источник данных» всегда «диск»). В этом случае к программе всё равно будет подключена сетевая библиотека, т.к. она упоминается в этом фрагменте кода. Но она использоваться не будет.

Чтобы не подтягивать в данном случае сетевую библиотеку компоновщик и компилятор должны быть достаточно умны, чтобы (а) выяснить, что вторая ветка кода никогда не будет вызываться и (б) суметь её вырезать. Если библиотека доступна в виде исходных текстов, то компилятор может (в теории) её вырезать. А если библиотека уже скомпилирована в машинный код, то вырезать её будет гораздо труднее — дополнительно потребуется сложный анализ машинного кода.

А исключить неиспользуемый код невозможно, поскольку определение недостижимости — алгоритмически неразрешимая задача. Т.е. невозможно написать анализатор кода, который для произвольной программы и произвольной строки кода в ней даст однозначный ответ вроде «строчка кода номер NNN никогда не выполняется» или «строчка кода номер NNN выполняется».

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

Но это теория. На практике обычно достаточно неточного ответа: «участок кода однозначно недостижим» / «недостижимость кода доказать невозможно».