Как «низкий» делает C как «низкоуровневый» язык? [закрыто]

17

Мы часто слышим, что C - это язык низкого уровня, но насколько он медленный? Самый низкий уровень, о котором я знаю, - это управление памятью с помощью указателей. Есть ли еще какие-то уровни, которые мне еще предстоит обнаружить? Что означает «близко к оборудованию»? Как «близко к оборудованию» является C?

    
задан ecounysis 16.02.2011 в 19:00
источник

12 ответов

20

Используйте стандартную терминологию. Языки более высокого уровня и языки нижнего уровня.

Языки высокого уровня предназначены для удобства лица, написавшего язык.

Языки нижнего уровня предназначены для простоты компьютера, на котором запущен язык.

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

Большинство операций C могут быть переведены на менее чем десять машинных инструкций. Некоторые могут быть переведены в единую машинную инструкцию (в зависимости от многих обстоятельств). Для сравнения, многие языки высокого уровня могут потребовать от десятков до тысяч машинных инструкций для реализации конкретной операции.

«Уровень» языка - это в основном абстрактное понятие. Это не полезно для многих, кроме сравнения одного языка с другим в контексте попытки понять, нужно ли вам писать больше исходного кода в том или ином виде, или вам нужно будет узнать больше об архитектуре машины на одном языке по сравнению к другому.

    
ответ дан Edwin Buck 16.02.2011 в 19:08
источник
5

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

    
ответ дан bta 16.02.2011 в 19:04
источник
4

C - это нечто большее, чем процедурная оболочка вокруг ASM. Хороший программист на C, который знает, что стоит за этим языком, должен иметь возможность взглянуть на фрагмент кода и записать ASM, в который будет скомпилирован код. Эти инструкции ASM могут быть переведены в 1: 1 на двоичные машинные инструкции. Это примерно на один шаг выше сборки, и как таковой вы можете написать код C, который делает что-то, на что способен компьютер, НО, находясь на таком низком уровне, он относительно примитивен с точки зрения того, о чем вы должны быть конкретным. Например, память рассматривается как таковая, а не абстрагируется в конструкциях, таких как «куча». Создание «нового» объекта на языке OO так же просто, как и так; эквивалентный C-код будет включать в себя malloc для суммы размера всех членов этого объекта и указывает на каждый из членов объекта внутри блока.

    
ответ дан KeithS 16.02.2011 в 19:04
источник
3

Лицо, создающее оборудование (процессор, материнская плата и т. д.), также предоставляет свой машинный язык (язык ассемблера). Это становится самым низким уровнем. Затем какой-то другой человек пишет компилятор для C, который преобразует синтаксис Си в собственный язык ассемблера для этого оборудования (пожалуйста, поправьте меня, если я ошибаюсь). С помощью C вы можете использовать сборку, и достигнут самый низкий уровень!

    
ответ дан Mr Coder 16.02.2011 в 19:06
источник
2

Определение «low» немного сложно, но C поддерживает ряд системных вызовов, gotos и даже сборку, перемещая через расширения.     

ответ дан Kevin Sylvestre 16.02.2011 в 19:03
источник
2

Чтобы ответить на этот вопрос, вам нужно определить, что вы подразумеваете под низким уровнем .

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

РЕДАКТИРОВАТЬ : это немного подробнее ...

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

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

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

Считалось, что

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

Вы не можете просто сказать «как уровень C?», вам нужно сделать обратное: определить, какой тип низкого уровня вам нужен, а затем посмотреть, может ли C это сделать.     

ответ дан peoro 16.02.2011 в 19:14
источник
1

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

Ниже вы можете запрограммировать MMU , что нелегко сделать на C, для этого обычно требуется очень зависимая от архитектуры сборка, и ваш код должен запускаться в виде привилегированного режима (как это делает ядро ​​ОС)

Также могут быть различные другие сопроцессоры или весь диапазон настроек>, это может быть трудно получить непосредственно в C.

    
ответ дан nos 16.02.2011 в 19:09
источник
1

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

Решение C должно было использовать два отдельных потока, обмениваясь семафорами. Но потоки не являются частью самого языка C.

    
ответ дан Tommy 16.02.2011 в 19:15
источник
1

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

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

При использовании в целом вместе со своей окружающей средой разработки прямолинейно иметь идеальный контроль над компоновкой памяти структур данных и общим размещением памяти. Разумеется, такой C-код в целом не переносится, поскольку он опирается на детали реализации компилятора, которые стандарт C позволяет гибко и на основе реализации. Но в целом сам код C может быть МОСТНО портативным. Это аспект языка - это то, что привело к его популярности в таких системах, как Unix, позволяя основной части ОС быть переносимой на всех машинах с минимальными специфическими для реализации конкретными аспектами реализации, которые, возможно, являются языком ассемблера.

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

Простым надуманным примером является что-то вроде:

int func(int a, int b) {
    int c;
    int d;

    d = 10;
    return a * d;
}

В простом компиляторе реализация может правильно выделить 4 int в стеке, 2 для аргументов и 2 для рабочих переменных. Очевидная оптимизация заключается в том, чтобы не выделять переменную 'c' вообще, поскольку она не используется. Дальнейшая оптимизация - игнорировать «d», а также использовать константу 10. И даже более умный компилятор может хорошо видеть, как этот func используется и встроить его автоматически в вызывающую функцию, полностью исключив вызов подпрограммы.

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

    
ответ дан Will Hartung 16.02.2011 в 19:22
источник
1

То, что я подразумеваю под низким уровнем, - это то, что каждый означает, когда говорят, что C - язык низкого уровня. Если бы я знал, что мне не нужно будет задавать вопрос. - ecounysis 27 секунд назад

Не похоже, чтобы вопрос выглядел вообще.

Если то, что вы хотите знать, означает то, что означает «низкий уровень», когда говорят, что в вики есть статьи, которые вы можете прочитать.

Ссылка

Ссылка

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

    
ответ дан user606723 16.02.2011 в 19:26
источник
0

Как насчет register ? Ключевое слово в объявлении локальной переменной, которое просит компилятор сохранить его в регистре CPU, хотя может игнорировать ваше предложение.

Однако GNU C расширяет это до точки, где вы можете указать конкретный регистр, который вы хотите использовать!

register int foo asm ("a5");
    
ответ дан Daniel Earwicker 16.02.2011 в 19:13
источник
-1

Тот факт, что вы задаете этот вопрос, выражает вашу наивность предмета. Это просто не так просто.

C не имеет полного гибкого языка ассемблера, но он приближается. Отсутствуют такие функции, как Tail Recursion

Но для большинства целей C делает все, что вам нужно - возможно, -

    
ответ дан user606723 16.02.2011 в 19:11
источник