Чтобы осуществлять контакты с внешним миром, программе нужно вводить и выводить информацию: открывать файлы, писать сообщения на экране, устанавливать сетевое соединение и т. д. Но разные компьютеры имеют разные аппаратные средства. Программа сама по себе не способна поддерживать все существующие типы экранов, звуковых карт или сетевых плат.
Вот почему в своей работе программы опираются на операционную систему. Благодаря ее помощи они легко работают с различными аппаратными средствами. Программы совершают специальные системные вызовы , чтобы ОС выполнила необходимые операции ввода-вывода. Компиляторы переводят команды ввода-вывода в надлежащие системные вызовы.
Однако разные ОС часто используют несовместимые системные вызовы. Системный вызов печати чего-либо на экране в Windows отличается от такового в Mac OS или Linux.
Вот почему, если вы компилируете программу для выполнения в Windows с процессором x86, она не будет работать в Mac с таким же процессором. Скомпилированный программный код должен быть ориентирован не только на конкретную архитектуру процессора, но и на конкретную операционную систему.
Оптимизация при компиляции
Хорошие компиляторы стараются оптимизировать машинный код, который они генерируют. Если они видят, что части вашего кода можно заменить более эффективными эквивалентами, они это сделают. Компиляторы порой применяют сотни правил оптимизации, прежде чем произвести двоичный код.
Именно поэтому вам не следует жертвовать простотой чтения кода в пользу его микрооптимизации. Компилятор так или иначе применит все тривиальные оптимизации. Посмотрите на этот фрагмент кода:
function factorial(n)
····if n > 1
········return factorial(n — 1) * n
····else
········return 1
Кто-то скажет, что его лучше заменить на этот эквивалент:
function factorial(n)
····result ← 1
····while n > 1
········result ← result * n
········n ← n — 1
····return result
Да, выполнение процедуры factorial без рекурсии использует меньше вычислительных ресурсов. Но это еще не повод менять программный код. Современные компиляторы автоматически перепишут простые рекурсивные функции. Вот еще один пример:
i ← x + y + 1
j ← x + y
Компиляторы избавятся от повторного вычисления x + y и сделают вот такое преобразование:
t1 ← x + y
i ← t1 + 1
j ← t1
Сосредоточьтесь на написании чистого и ясного программного кода. Если у вас есть проблемы, связанные с производительностью, используйте инструменты профилирования для обнаружения узких мест в вашем программном коде и пробуйте реализовать эти части более умными способами. Не стоит напрасно тратить время на ненужную микрооптимизацию.
Впрочем, иногда этап компиляции просто отсутствует. Давайте посмотрим, что это за ситуации.
Некоторые языки программирования, так называемые языки сценариев, выполняются без прямой компиляции в машинный код. К ним относятся JavaScript, Python и Ruby. Код на этих языках выполняет не центральный процессор непосредственно, а интерпретатор — программа, которая должна быть установлена на компьютере.
Так как интерпретатор переводит программный код в машинный в режиме реального времени, тот обычно работает намного медленнее скомпилированного кода. С другой стороны, программист может выполнить код, не ожидая окончания компиляции. Когда проект очень большой, компиляция иногда занимает несколько часов.
Инженерам Google приходилось постоянно компилировать большие пакеты кода. Это заставляло разработчиков терять (рис. 7.9) много времени. В Google не могли переключиться на языки сценариев — нужна была максимальная производительность скомпилированного двоичного файла. Поэтому они разработали Go — язык, который компилируется невероятно быстро и имеет очень высокую производительность.
Рис. 7.9.Компиляция [78] Любезно предоставлено http://xkcd.com .
Дизассемблирование и обратный инженерный анализ
Восстановить исходный код скомпилированной программы — тот, что был до момента компиляции, — нельзя [79] По крайней мере, на данный момент. С развитием искусственного интеллекта это когда-нибудь окажется возможным.
. Но можно декодировать бинарную программу, трансформировав числа, в которых закодированы команды ЦП, в последовательность команд, более-менее понятную для человека. Этот процесс называется дизассемблированием .
Читать дальше
Конец ознакомительного отрывка
Купить книгу