Pull to refresh

Comments 27

* да, я понимаю, что «низкий уровень» — это субъективный термин.
Примечание: у каждого разработчика C# своё представление о том, что такое «низкий уровень» ...
Всегда считал, что низкоуровневое программирование, это возможность использования аппаратно-специфичных инструкций и прямое взаимодействие с железом.
В отличии от языков программирования высокого уровня, которые независимы от аппаратной платформы.

Есть платформозависимые интристики (в основном для SIMD-инструкций), которые работают только на конкретной платформе (x86, ARM итп)

Так же как и на ассемблере при работе в user mode — никак. Если мы говорим про режим ядра, то "обработка прерываний" обычно состоит в настройке таблицы векторов обработчиков и относительно небольших архитектурозависимых трамплинах. При желании трамплины могут идти прямо в шарпокод. См. Singularity для деталей реализации.

архитектурозависимых трамплинах
Что это такое? Ради интереса погулил, вылезают только лыжи.

А если это используется только в исследовательском проекте по разработке операционной системы Singularity, то вот цитата из этой статьи:
Подход Singularity снова очень прост — вся система написана целиком на C#, лишь малая часть написана на C++ и ассемблере.
Подозреваю, что это и есть те самые аппаратно-зависимые части, которые на С# реализовать нет возможности. Именно как раз из-за того, что С# не является языком низкого уровня.
Из чего также можно сделать вывод что C++ тоже не является языком низкого уровня. Часть которую на нем нельзя написать, написана на ассемблере.
Такой вывод сделан на основании цитаты, вырванной из контекста
написана на C++ и ассемблере
Хотя мне, например, не известно, чем руководствовались разработчики Microsoft, вполне возможно, что оптимизировали отдельные участки кода.

Но таки да, С++ действительно следует относить к языкам высокого уровня ;-)
Что это такое? Ради интереса погулил, вылезают только лыжи.

Ну вот смотрите, пишете вы свою ОС на C. Прилетает вам управление в вектор прерывания. А у C вообще говоря есть соглашения вызова процедур, по которым процедуры могут делать любую фигню с рядом регистров и при выходе из себя возвращают управление определённым образом.


А у конкретной аппаратной архитектуры при возникновении прерывания текущий IP (instruction pointer) сбрасывается в какой-то неиспользуемый сишным компилятором регистр, остальные, регистры остаются как были в выполнявшемся до этого коде, а возврат из прерывания надо делать специальной ассемблерной инструкцией.


Чтобы как-то с этим жить на ассемблере пишется небольшой кусок кода (trampoline), который сохраняет куда-нибудь регистры и делает вызов вашего "настоящего" обработчика по правильной конвенции, а потом возвращает всё взад как было. Ну или не возвращает, а пинает планировщик, чтобы тот сохранил контекст для текущего потока. Зависит.


При разработке ОС вообще часто приходится писать сравнительно небольшие куски кода на асме, потому что иначе просто вообще никак.

Вы описали пролог функции, а не трамплин.
Трамплин используется для упрощения взаимодействия с библиотеками.
Например, вы хотите получить текущее время.
Компилятор создает секцию импорта со списком используемых функций.
Загрузчик, видя, что требуется функция времени, загружает нужную библиотеку, вычисляет адрес функции времени и вписывает его туда, куда ранее загрузил секцию импорта(таблицу переходов).
Чтобы не работать с косвенными адресами, адреса хранятся в виде команд перехода на реальное тело функции. Эти команды и называются трамплином.
То есть, когда в коде записано gettime,
реально процессор вызывает call GOT + offset_of_gettime_in table,
где расположена команда jmp real_offset_of_gettime

Не приметили только слона =)

Ведь C#/IL-код выполняется именно поверх слона — машиной CLI/CLR, которая внезапно написана на С++.

О каком низком уровне можно говорить?
А вот о низкоуровневых возможностях — вполне.

Не совсем написана. C++ используется там на 30%.

Не путаешь с самым .net фреймворком, который написан на C#?

В любом случае пруф бы не помешал.

В данном случае я не разделяю С/С++
Скачал и посмотрел — на С# там как раз только библиотека и написана.

А основа на С++.

В CoreRT рантайм практически весь на C# уже. В изделии от Unity в принципе тоже. В JIT-based рантаймах, да, много либо C, либо C++.

Тоже кажется, что вопрос в статье поставлен некорректно. Правильнее было бы "Можно ли на C# писать быстрый код?". С учётом окончания статьи с натяжкой можно было бы спросить "Можно ли на C# писать системный код?" (хотя это вопрос не столько к языку, сколько к платформе). Ну а что касается того, является ли C# низкоуровневым, то мое мнение не изменилось: нет, не является.

Согласен, потому что у него есть среда исполнения. А без нее это будет немного не тот C# к которому мы привыкли.

Ребята из Unity потиху переписывают кишки рантайм с C++ на C#, т.к. их рантайм дает им гибкость и лучший alias analysis для качества выходного кода (используется своя прокладка для трансляции IL в LLVM IR где уже потом используются все те же самые оптимизации что и в clang). Так что в целом C# вполне способен на близкий к С++ аутпут ;-)

Вы тоже верите что у них получится что-то вменяемое? :)
Тоже показалось странным, что код на C# автор оптимизирует, а на C++ почему-то считает идельным.

Интересно было бы посмотреть, как бы изменилась производительность, если бы использовался unsafe код
Хотя список оптимизаций из твиттера и без этого страшный конечно :)

Спасибо за интересную и полезную статью!

Раньше си ошибочно низкоуровневым называли, теперь c#, ждём статью «низкоуровневый JavaScript»
Надеюсь, низкоуровневость закончится там, где закончится машина Тьюринга. А то у нас и SQL с HTML пойдут в низы.
К сожалению проблема C# в том, что он определяет templates во время выполнения, когда С++ во время компиляции. В сущности это проблема JIT, а следовательно нерационального использования памяти и возрастание page fault errors. Впрочем это успешно компенсируется низкой стоимостью разработки.
Sign up to leave a comment.

Articles