Почему для программирования на C нужен компилятор, а для сценариев оболочки - нет?

Я использую opensuse. Я установил abootimg. Если вы хотите извлечь (boot|recovery).img, запустите such:

abootimg -x (boot|recovery).img

Затем вы получите следующие файлы: bootimg.cgf, zImage и initrd.img. Если вы хотите упаковать образ, выполните such

abootimg --create (boot|recovery).img -f bootimg.cfg -k zImage -r initrd.img

Затем вы получите (boot|recovery).img

Enjoy

8
16.12.2016, 19:04
6 ответов

Это означает, что сценарии оболочки не компилируются, а интерпретируются: оболочка интерпретирует сценарии по одной команде за раз и каждый раз выясняет, как выполнить каждую команду. Это имеет смысл для shell-скриптов, поскольку они все равно тратят большую часть своего времени на выполнение других программ.

Программы на языке Си, с другой стороны, обычно компилируются: прежде чем их можно запустить, компилятор преобразует их в машинный код полностью, раз и навсегда. В прошлом существовали интерпретаторы Си (например, интерпретатор Си от HiSoft на Atari ST), но они были очень необычными. В настоящее время компиляторы Си очень быстры; TCC настолько быстр, что вы можете использовать его для создания "сценариев Си", с #!/usr/bin/tcc -run shebang, так что вы можете создавать программы на Си, которые выполняются так же, как сценарии оболочки (с точки зрения пользователей).

Некоторые языки обычно имеют и интерпретатор, и компилятор: BASIC - один из примеров, который приходит на ум.

Вы также можете найти так называемые компиляторы сценариев оболочки, но те, которые я видел, являются просто обертками для маскировки: они по-прежнему используют оболочку для интерпретации сценария. Как отмечает mtraceur, хотя правильный компилятор сценариев оболочки, конечно, был бы возможен, просто не очень интересен.

Другой способ думать об этом - считать, что возможность интерпретации сценариев в оболочке является расширением возможностей командной строки, что естественно приводит к интерпретируемому подходу. С другой стороны, язык C был разработан для создания автономных двоичных файлов, что приводит к компилируемому подходу. Языки, которые обычно компилируются, тоже склонны к появлению интерпретаторов или, по крайней мере, парсеров командной строки (известных как REPLs, read-eval-print loops; оболочка сама по себе является REPL).

24
27.01.2020, 20:08

Представьте, что английский не является вашим родным языком (это может быть довольно легко для вас, если английский не является вашим родным языком).

Вы можете прочитать это тремя способами:

  1. (Устный перевод) Во время чтения переводите каждое слово каждый раз, когда вы его видите.
  2. (Оптимизированный-интерпретируемый) Найдите общие фразы (например, «ваш родной язык») , переведите их и запишите. Затем переведите каждое слово - кроме уже переведенных фраз
  3. (Скомпилировано) Попросите кого-нибудь перевести весь ответ

У компьютеров есть своего рода «родной язык» - комбинация инструкций, которые понимает процессор. , а также инструкции, понятные операционной системе (например, Windows, Linux, OSX и т. д.). Этот язык не читается людьми.

Языки сценариев, такие как Bash, обычно делятся на категории 1 и 2. Они берут строку за раз, переводят эту строку и запускают ее, а затем переходят к следующей строке. На Mac и Linux по умолчанию установлено довольно много разных интерпретаторов для разных языков, таких как Bash, Python и Perl. В Windows их нужно установить самостоятельно.

Многие языки сценариев выполняют небольшую предварительную обработку - попробуйте ускорить выполнение, скомпилировав фрагменты кода, которые будут выполняться часто или которые в противном случае замедлили бы работу приложения. Некоторые термины, о которых вы, возможно, слышали, включают опережающую (AOT) или своевременную (JIT) компиляцию.

Наконец, скомпилированные языки - такие как C - переводят всю программу, прежде чем вы сможете их запустить.Это имеет то преимущество, что перевод может быть выполнен на машине, отличной от выполняемой, поэтому, когда вы передаете программу пользователю, хотя ошибки все еще могут быть, некоторые типы ошибок уже могут быть устранены. Также как если бы вы дали это своему переводчику, и я упомянул, как garboola mizene resplunks , это может показаться вам правильным английским, но переводчик может сказать вам, что я несу чушь. Когда вы запускаете скомпилированную программу, ей не нужен интерпретатор - она ​​уже на родном языке компьютера.

Однако у скомпилированных языков есть один недостаток: я упоминал, что у компьютеров есть собственный язык, состоящий из функций из оборудование и операционная система - ну, если вы компилируете свою программу в Windows, вы не ожидаете, что скомпилированная программа будет работать на Mac. Некоторые языки обходят это путем компиляции в своего рода промежуточный язык - немного похожий на Pidgin English - таким образом вы получаете преимущества скомпилированного языка, а также небольшое увеличение скорости, но это означает, что вам нужно объединить интерпретатор с вашим кодом (или используйте тот, который уже установлен).

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

3
27.01.2020, 20:08

Все сводится к технической разнице между тем, как программа, которую вы можете читать / писать как человек, преобразуется в машинные инструкции, понятные вашему компьютеру - а различные преимущества и недостатки каждого метода являются причиной того, что некоторые языки написаны так, что нуждаются в компиляторах, а некоторые написаны для интерпретации.

Во-первых, техническая разница

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

В основном есть две общие категории языков программирования:

  1. Другая программа («компилятор») читает вашу программу, определяет какие шаги говорит ваш код, а затем пишет новую программу в машинном коде («языке», который понимает сам ваш компьютер), которая выполняет эти шаги.
  2. Другая программа («интерпретатор») считывает вашу программу, определяет, какие шаги указывает ваш код, а затем выполняет эти шаги самостоятельно . Никакой новой программы не создается.

C относится к первой категории (компилятор C переводит язык C в машинный код вашего компьютера : машинный код сохраняется в файл, а затем, когда вы запускаете этот машинный код, он делает то, что вы хотите).

bash относится ко второй категории (интерпретатор bash считывает язык bash , а интерпретатор bash делает то, что вы хотите: поэтому нет никакого «модуля компилятора» как такового, интерпретатор выполняет интерпретацию и выполнение, тогда как компилятор выполняет чтение и перевод).

Возможно, вы уже заметили, что это означает:

С помощью C вы выполняете шаг «интерпретации» один раз , а затем всякий раз, когда вам нужно запустить программу, вы просто говорите своему компьютеру выполнить машинный код - ваш компьютер может просто запустить его напрямую, без лишних "размышлений".

В bash вы должны выполнять шаг «интерпретации» каждый раз, когда запускаете программу - на вашем компьютере работает интерпретатор bash, а интерпретатор bash дополнительно «думает», чтобы выяснить, что он нужно делать для каждой команды каждый раз.

Таким образом, программам на C требуется больше ЦП, памяти и времени для подготовки (этап компиляции), но меньше времени и работы для выполнения. Программы bash требуют меньше ЦП, памяти и времени для подготовки, но больше времени и работы для выполнения. Вы, вероятно, не замечаете этих различий большую часть времени, потому что в настоящее время компьютеры очень быстрые, но это действительно имеет значение, и эта разница складывается, когда вам нужно запускать большие или сложные программы или много маленьких программ.

Кроме того, поскольку программы C преобразуются в машинный код («родной язык») компьютера, вы не можете взять программу и скопировать ее на другой компьютер с другим машинным кодом (например, Intel 64-bit на 32-разрядную версию Intel или с Intel на ARM, MIPS или что-то еще).Вы должны потратить время, чтобы снова скомпилировать его для другого машинного языка . Но программу bash можно просто перенести на другой компьютер, на котором установлен интерпретатор bash, и она будет работать нормально.

Теперь часть вашего вопроса почему

Создатели C писали операционную систему и другие программы на аппаратном обеспечении несколько десятилетий назад, что было довольно ограничено современными стандартами. По разным причинам преобразование программ в машинный код компьютера было для них лучшим способом достижения этой цели в то время. Кроме того, они выполняли такую ​​работу, когда было важно, чтобы написанный ими код выполнялся эффективно .

А создатели оболочки Bourne и bash хотели обратного: они хотели писать программы / команды, которые можно было бы выполнять немедленно - в командной строке, в терминале, вы хотите просто написать одну строку, одну команду, и заставить его выполнить. И они хотели, чтобы написанные вами сценарии работали везде, где у вас установлен интерпретатор / программа оболочки.

Заключение

Короче говоря, вам не нужен компилятор для bash, но он нужен для C, потому что эти языки по-разному преобразуются в фактические действия компьютера, и этот другой способ сделать это был выбран, потому что в языках разные цели.

Прочие технические / дополнительные сведения / примечания

  1. Фактически вы можете создать интерпретатор C или компилятор bash . Ничто не мешает этому: просто эти языки были созданы для разных целей.Часто проще просто переписать программу на другом языке, чем написать хороший интерпретатор или компилятор для сложного языка программирования. Особенно, когда в этих языках есть что-то, в чем они хороши, и они изначально были разработаны с учетом определенного стиля работы. C был разработан для компиляции, поэтому в нем отсутствует множество удобных сокращений, которые вы хотели бы использовать в интерактивной оболочке, но он очень хорош для выражения очень конкретных низкоуровневых манипуляций с данными / памятью и взаимодействия с операционной системой. , которые вы часто выполняете, когда хотите написать эффективно скомпилированный код. Между тем, bash очень хорош для выполнения других программ, перенаправления файлов / файловых дескрипторов и работы со строками текста, и у него есть удобное сокращение для них, потому что это задачи, которые вы часто хотите выполнять в интерактивной оболочке.

  2. Более подробная информация: на самом деле существуют языки программирования, которые представляют собой смесь обоих типов (они переводят исходный код «большую часть пути», так что они могут выполнять большую часть интерпретации / «мышления» один раз, и только немного об интерпретации / "мышлении" позже). Java, Python и многие другие современные языки на самом деле являются такими смесями: они пытаются дать вам некоторые преимущества переносимости и / или быстрой разработки интерпретируемых языков, а также некоторую скорость компилируемых языков. Есть много возможных способов комбинировать такие подходы, и разные языки делают это по-разному.Если вы хотите углубиться в эту тему, вы можете прочитать о компиляции языков программирования в «байт-код» (что похоже на компиляцию в ваш собственный придуманный «машинный язык», который вы затем можете интерпретировать быстро и эффективно) и «JIT». "(Точная компиляция,где вы компилируете и, возможно, даже перекомпилируете программу по мере ее интерпретации или запуска).

  3. Вы спросили о бите выполнения: на самом деле исполняемый бит нужен только для того, чтобы сообщить операционной системе, что этот файл разрешен для выполнения. Я подозреваю, что единственная причина, по которой сценарии bash работают для вас без разрешения execute , на самом деле заключается в том, что вы запускаете их из оболочки bash. Обычно операционная система, когда ее просят выполнить файл без установленного бита выполнения, просто возвращает ошибку. Но некоторые оболочки, такие как bash, увидят эту ошибку и возьмут на себя выполнение файла в любом случае, в основном эмулируя шаги, которые обычно выполняет операционная система (найдите строку "#!" В начале файла и попробуйте для выполнения этой программы для интерпретации файла со значением по умолчанию либо он сам, либо / bin / sh , если нет строки «#!»).

  4. Иногда компилятор уже установлен в вашей системе, а иногда IDE поставляются со своим собственным компилятором и / или запускают компиляцию за вас. Это может сделать скомпилированный язык «некомпилированным» языком для использования, но техническая разница все же присутствует.

  5. «Скомпилированный» язык не обязательно компилируется в машинный код, и вся его компиляция - это отдельная тема. По сути, этот термин используется широко: на самом деле он может относиться к нескольким вещам. В определенном смысле «компилятор» - это просто переводчик с одного языка (обычно это язык «более высокого уровня», более простой для использования людьми) на другой язык (как правило, язык «более низкого уровня», который проще использовать для компьютеров - иногда, но на самом деле не очень часто, это машинный код). Кроме того, иногда, когда люди говорят «компилятор», они на самом деле имеют в виду несколько программ, работающих вместе (для типичного компилятора C на самом деле это четыре программы: «препроцессор», сам компилятор, «ассемблер» и « компоновщик ").

8
27.01.2020, 20:08

Рассмотрим следующую программу:

2 Mars Bars
2 Milks
1 Bread
1 Corn Flakes

В методе bash вы бродите по магазину в поисках батончиков Марса, наконец находите их, затем бродите в поисках молока и т. Д. Это работает, потому что вы запуск сложной программы под названием «Опытный покупатель», которая может распознать хлеб, когда вы видите все без исключения сложности покупки. bash - довольно сложная программа.

Вы также можете передать список покупок составителю покупок. Компилятор немного подумает и выдаст вам новый список. Этот список ДЛИННЫЙ , но состоит из гораздо более простых инструкций:

... lots of instructions on how to get to the store, get a shopping cart etc.
move west one aisle.
move north two sections.
move hand to shelf three.
grab object.
move hand to shopping cart.
release object.
... and so on and so forth.

Как видите, компилятор точно знает, где все находится в магазине, поэтому вся фаза «поиска вещей» не нужна.

Это самостоятельная программа, для выполнения которой не требуется «Опытный покупатель». Все, что ему нужно, - это человек с «базовой человеческой операционной системой».

Возвращаясь к компьютерным программам: bash - это «опытный покупатель», он может взять сценарий и просто сделать это, ничего не компилируя. Компилятор C создает автономную программу, для запуска которой больше не требуется никакой помощи.

И интерпретаторы, и компиляторы имеют свои преимущества и недостатки.

6
27.01.2020, 20:08

Языки программирования/сценариев могут быть скомпилированными или интерпретированными.

Скомпилированные исполняемые файлы всегда быстрее, и многие ошибки могут быть обнаружены до выполнения.

Интерпретируемые языки обычно проще в написании и адаптации, они менее строгие, чем компилируемые, и не требуют компиляции, что облегчает их распространение.

5
27.01.2020, 20:08

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

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

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

1
27.01.2020, 20:08

Теги

Похожие вопросы