Обновить
2
0.5

Пользователь

Отправить сообщение

Ну что, раз вы понимаете как рассказывать про форматирование без С-ABI, то объясните почему оно так работает, почему мне надо писать те или иные значки и как "компилятор" понимает что и как подставить в код:

почему работает printf("%d %lu", int_var, long_u_var))

ПС
Ну и прикол с Python в том, что в принципе за первую половину пары можно рассказать почти всё про утиную типизацию:
- программа в Python выполняется построчно интерпретатором.
- любая переменная в Python это объект
- интерпретатор понимает (знает в runtime) какие функции есть у объекта.
- когда вы делаете что угодно с объектом, это почти всегда значит, что интерпретатор берёт у объекта соответствующую функцию и выполняет её (или обрабатывает ситуацию отсутствия функции - почти всегда это исклюение).

> Нужно ли знать про кишки VM .NET для объяснения форматирования в C#?
Зачем вы задаёте этот вопрос, если я уже объяснял в чём разница в этом месте между C и условными Python и Rust?

Для С# - надо понимать как VM смотрит на наличие метода у объекта и дёргает его, а для C - аналогичные объяснения потребуют солидную такую часть курса "архитектура ЭВМ" прочитать. Что в рамках изучения первого языка малореально.

ПС
И да если кто-то смог выучиться в тяжёлых и неподходящих условиях не непонятном уровне (а вот вся наша компьютерная подгруппа не смогла нормально выучить С как второй язык в 10 классе - ровно потому, что мы не получали нормальный объяснений "как" и "почему") - это не значит, и всех надо мучить преподавая в таких же неподходящих условиях.

Ровно все эти концепции есть в других языках,

Очень не так. Там они спрятаны за абстракцией объекта \ модуля. А в Си - машинерия наружу.

И да я посмотрю как вы побъясните C call ABI (почему работает printf("%d %lu", int_var, long_u_var)) в на второй паре.

(ответил чуть продробнее выше)
https://habr.com/ru/articles/739452/comments/#comment_25649448

Пока ваш ученик "прилежная маша-отличница" делает записи в тетрадку и когда нужно что-то делать повторяет по бумажке - всё ок.
Как только вы получите живого и любознательного ученика которому надо понять прежде чем делать вам придётся объяснять "почему". А при объяснении почему вы столкнётесь с тем, что в С почти всё кишками наружу (нет уровня абстракции между представлением в языке и поддержкой в ОС).

#include

А зачем там стоит знак "#" почему бы не написать просто include?
(почему мы пишем имя файла, а не подуля - от более продвинутого польозателя).
Кажется тут вам надо начать рассказывать про препроцессор и линкер.

Выводит в STDOUT форматированную строку, %d применяется для подстановки в строку целых чисел в десятичной системе.

Ох зря вы про stdout начали - кажется это отдельная лекция про устройстов ОС на пол-пары минимум.

Ну это мягко говоря не совсем так. Целых (в смысле int) знаковых. А для long \ short - свои спецификаторы. А почему это работает и именно так? Кажется вам придётся рассказать про ABI вызовов языка Си (как вы увлекательно при вызове кладёте аргументы на стек, а потом достаёте их и как вы в процессе парсинга строки с этими аргументами работаете).
Вот в Паскале вы можете сказать "компиляторная магия" (компилятор знает тип числа и генерирует для вас код) на Python - всё есть объект, имплементирующий специальный метод __str_, в Rust - специальный трэйт Debug \ Show...

int main()

...

return 0

Для "совсем 0" вам придётся рассказать, как программа взаимодействует с ОС. И подозреваю, что обычный выпускник 11 класса может этого не знать.
Для "не совсем 0" - тоже будет пара сюрпризов с упоминанием ф-ии __start_ и стандартной библиотеки (почему возвращаемый main тип не совпадает с $? в баше?).

Например, для ядра Windows во всем Microsoft код пишут всего около дюжины человек.

При любом разумном способе опредленения "ядра windows" это не может быть правдой просто из-за размера кодовой базы.

Несомненно сегодня курсы создают кучу проблем всем "нанимающим" (ну мы, например людей только с курсами в VC не рассматриваем).

Но в недалёкой перспективе они могут привести к положительным сдвигам в отрасли.
Когда институт будет аналогом "института" а курсы аналогом "техникума". На мой взгляд этого у нас в IT сильно не хватает.

В С сложных концепций нет

#include <stdio.h>
int main() {
    printf("%d\n", 5);
    return 0;
} 

Хм интересно вы за 1 академическую пару успеете объяснить полному новичку в программировании что и почему делается так в этой программе?

я программист.
наши dev-ops вот буквально неделю назад перенесли часть серверов на виртуалки.

На одном из серверов крутятся одновременно cpu-bound и disk-bound задачи.
Прямо сейчас (час назад) вижу, что disk-bound задача просела в тысячи раз. Сидят, разбираются. Краткое краткое резюме в момент описания задачи - сделали всё по инструкции "вписать название технологии" испортится ничего не могло.

Всё бы хорошо, но боюсь заказчикам такое объяснение не подойдёт (разумеется ребята толковые, всё починят - но вот этот подход "мы знаем инструменты" иногда подбешивает).

Спасибо.
Получается, хардкорно заоптимизировали.
На уровне ad-hoc типов данных в IR (обойтись просто запуском доп фазы компиляции не получилось).

Хотел задать вопрос по LLVM не связанный непосредственно с темой поста.

А как там решается проблема того, что некоторые фронтэнды разрешают неэквивалентные преобразования (например С и С++ UB таковыми являются)?
(как my best guess - должен быть флаг, в зависимости от которого запускать дополнительный набор peep-hole правил, но хотелось бы послушать как оно на самом деле).

Ведь если обрабатывать С \ С++ UB строгим образом - получите просадку производительности.
Но закладываться на С \ С++ UB очевидно тоже нельзя (иначе нельзя было бы использовать LLVM как бэкэнд для более строгих языков, того же Rust \ Haskell \ D \ ...).

============================================================
Т.е. условно если у вас есть:
a: i32;
if (a + 1 > a) { do_1() } else {do_2() };

gcc -O2 - скорее всего всегда будет выполняться do_1().
cargo run --release (rust) - будет делаться честная проверка и при переполнении выполняться do_2().

Обычно "сосед с перфоратором" не профи - в итоге он делает работу низкотехнологично не только сверлит, а вообще всё.

В итоге какая разница - он сверлит 10 секунд через 10 минут в течении 2 часов. Или 1 минуту через 10 минут в течении 2 часов. В обоих случаях твой "отдых" испорчен.

Если "чистое время сверления" - это 2 минуты. Интервалами по 10 секунд в течении 2 часов - вам сильно проще будет?

Я кажется взвешенных статей по тесле вообще не видел.
Либо обожание либо ненависть.

Мне кажется это и в целом к Маску относится.

Но мне неизвестно всегда ли одному и тому же раскладу соответствует
строго одно расположение мин. Это похоже на правду, но доказать я не
могу.

Очевидно что нет.
Неоднозначность в сапёре - это и есть 2 решения одной и той же позиции в минёре.

Ваш вариант короче, вариант nikto_b удачнее (более понятен).

нет не то написал.

Автор извините, но у вас какая-то посконная поп-психология, не поделу.
Вы путаете "быть управляемым / слабохарактерным" и "быть хорошим".

  1. Из социологии и криминалистики - человек действительно хочет быть хорошим. Если человек, себя таковым не считает - маркер психиатрических проблем.

  2. Общество "хороших" людей (не путать хороший и слабохарактерный) - действительно считается более экономически успешным (погуглитехотя бы рейтин издержек стран из-за отсутствия доверия - по простому сколько % ВВП каждая страна недосчитывается из-за мошенничества \ обманов \ юристов...).

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

Дам ещё один совет (он у меня вырос на распробовании Haskell - но Rust, во многом, его идеями вдохоновлялся (в купе с zero cost abstractions)).

- Стараться пользоваться иммутабельными данными
- Создавать новые структуры данных при необходимости (используя map \ filter \ reduce)
- в развитии предыдущего: стараться, чтобы каждой переменной вы могли дать обозначение в терминах "бизнес-логики" что примерно эквивалентно "одинаковому уровню абстракции в рамках одной функции".

Оптимизаций разных под разные типовые use-case можно много разных придумать (*).
Спросил потому, что вы хорошо поставленным уверенным тоном про дисковую подсистему писали - я правильно понял что конкретный вопрос не по адресу.

*) Например при последовательном чтении с начала страницы запоминать кол-во записанных байт, в случае не выполнения оптимизации - читать с диска, больше не применять к файлу.

Это разумеется. Но вопрос немного про другое.
Вот смотрите как это работает при очевидной реализации:

В общем случае мы должны гарантировать консистентность состояния нашего файла (и даже не столь важно у нас MAP_PRIVATE \ MAP_SHARED_*** ).
При наивной реализации мы при записи первого же байта в страницу отображённую на диск мы обязаны:
1. Сказать, что теперь эта страница отображена в память, а значит:
1.а) прочитать всю страницу с диска в mmap-образ в памяти.
1.б) записать этот 1 байт данных в в mmap-образ в памяти.
2. Работаем дальше. Когда надо будет - скинем всю страницу на диск.

Так вот есть ли в Linux какая-то оптимизация, позволяющая убрать пункт 1.а) ?

У меня выше вопрос очень похожий.

Как избежать лишних чтений при mmap && записи достаточно больших блоков.

Т.е. открываем мы через mmap существующий файл и пишем туда "много" информации.
Как технически linux избегает "лишних" чтений из тех блоков диска, которые всё равно будут полностью перезаписаны?

Информация

В рейтинге
2 125-й
Зарегистрирован
Активность