LINUX.ORG.RU
ФорумTalks

Rust обогнал Сишечку по скорости распаковки

 , ,


0

6

Привет, ЛОР!

Случилось непредвиденное и невероятное: реализация библиотеки zlib на Rust (zlib-rs) обогнала реализацию на C по скорости распаковки и показывает примерно схожую с последней скорость запаковки данных. Разница в производительности может достигать аж 14%.

Есть ли смысл теперь вообще писать новый софт на Си, если даже в производительности он начинает терять лидерство? Что скажут эксперты по Си и почему zlib на Си так плохо оптимизирован?

Ссылка на бенчмарки: https://trifectatech.org/blog/zlib-rs-is-faster-than-c/

Перемещено dataman из development

★★★★★

Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от LightDiver

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

Круто, но думаю дело не в ЯП. Само погромирование не зашло или вы выбрали задачи которые вам не зашли на тот момент.

anc ★★★★★
()
Ответ на: комментарий от anc

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

Да, всё так. Только это не мешает тому факту, что на дизайн языка Си очень сильно повлиял ассемблер PDP-11. А к другим ассемблерам Си относится примерно никак и близости никакой нет.

Наследники оригинальной кодовой базы UNIX мертвы

С оригинальной там с самого начала не зашло, но не по причине того что оно плохое, а чисто юридические разборки, at&t долго пыталась на себя одеяло перетащить и доказать что «это все мое родное и нажито непосильным трудом».

AT&T распилили на молекулы в начале 80х, они никуда не пытались. Пытались потом перцы типа SCO и подобные. Но, опять же, факт в том, что Solaris и прочие AIX могут содержать куски оригинальной UNIX, потому что его код был лицензирован авторам этих ОС. А Linux и BSD такого кода не содержат.

Ну да… конечно… и /dev уже закопали и пайпы запретили…

Никто ничего не запрещал. Но современный линуксовый софт дёргает dbus или – куда хуже! – HTTP, а не пайпами общается. Последним гробом в крышку UNIX было внедрение polkit/consolekit и в итоге systemd. После них никаким юниксом в линуксе не пахнет, если не считать пары ретроградских дистров без ничего.

hateyoufeel ★★★★★
() автор топика
Ответ на: комментарий от anc

Программирование зашло. Но у меня не было: 1) Компьютера 2) Учебников 3) Тех, кто хоть что то бы подсказал.

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

Я и два года назад начал то только благодаря LINUX.ORG.RU - пользователя такого тут. Он мне дал пинок в виде скрипта луа и подсказал по началу. И еще одного пользователя, который подсказывал в irc. Без них хер бы я что начал.

LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Только это не мешает тому факту, что на дизайн языка Си очень сильно повлиял ассемблер PDP-11.

Да вроде тоже нет.

AT&T распилили на молекулы в начале 80х, они никуда не пытались.

Во первых не совсем на молекулы, а емнип на три части, а во вторых очень даже пытались.

Пытались потом перцы типа SCO и подобные.

Это была уже другая история, более поздняя.

Но, опять же, факт в том, что Solaris и прочие AIX могут содержать куски оригинальной UNIX

Могут содержать, а могут не содержать, лет много прошло.

А Linux и BSD такого кода не содержат.

Это да.

Но современный линуксовый софт дёргает dbus или – куда хуже! – HTTP, а не пайпами общается.

Понятие «современный линуксовый софт» это что-то сферичное.

Последним гробом в крышку UNIX было внедрение polkit/consolekit

Эм... разверните свою мысль пожалуйста.

и в итоге systemd

Оно много где есть, но не везде.

anc ★★★★★
()
Ответ на: комментарий от LightDiver

Программирование зашло. Но у меня не было: 1) Компьютера 2) Учебников 3) Тех, кто хоть что то бы подсказал.

Ну значит не зашло :) А если серьезно, то ЯП в таких условиях тем более ни при чем.

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

Сочувствую.

Я и два года назад начал то только благодаря LINUX.ORG.RU - пользователя такого тут. Он мне дал пинок в виде скрипта луа и подсказал по началу. И еще одного пользователя, который подсказывал в irc. Без них хер бы я что начал.

Годно!

anc ★★★★★
()
Ответ на: комментарий от anc

Только это не мешает тому факту, что на дизайн языка Си очень сильно повлиял ассемблер PDP-11.

Да вроде тоже нет.

Да. В Си нет ничего про ближние/дальние указатели и сегментную модель памяти, которая была в x86, например. Про кеши Си тоже не знает. И это ещё довольно распространённая архитектура. А если мы возьмём Лисп-машины или, ещё хуже, какой-нибудь iAPX432 с хардварной поддержкой ООП, там Си фактически с другой планеты будет.

Могут содержать, а могут не содержать, лет много прошло.

Несколько лет назад читал про солярку, что какие-то куски там ещё оставались, в том числе в OpenSolaris.

Понятие «современный линуксовый софт» это что-то сферичное.

Да нет, это вполне конкретные вещи: софт, работающий под Linux и написанный в последние 10 лет.

Последним гробом в крышку UNIX было внедрение polkit/consolekit

Эм… разверните свою мысль пожалуйста.

В Линукс давно уже нет концепции «всё – файл». Сейчас есть концепция «всё – fd», даже вещи, которые файлами не являются и на файловой системе отсутствуют. Память, сигналы, модераторы ЛОРа^W^W. Это гораздо ближе к модели NT с хэндлами. Например, fd можно передать в другой процесс по dbus, а файл – нельзя.

Вместе с этим, контроль за доступом сместился со статичных юниксовых прав на динамический фреймворк под названием PolicyKit, где конфигурация описывается вообще на JavaScript и эти правила являются Тьюринг-полными. Вместо статичных терминалов – концепт из seats, который появился в виде ConsoleKit и потом был инкорпорирован в systemd.

В общем, современный Linux к оригинальному UNIX имеет куда меньше отношения, его архитектура куда больше напоминает Windows. Что в принципе не так плохо, потому что Windows NT далеко не самые глупые люди проектировали и их опыт учитывал в том числе 20 лет существования UNIX систем.

Оно много где есть, но не везде.

Да, в Android его нет, это вообще отдельная экосистема. Но я предлагаю не считать Android линуксом, когда речь идёт о линукс-системах в традиционном смысле. То есть, Linux + GNU + Xorg/Wayland.

hateyoufeel ★★★★★
() автор топика
Последнее исправление: hateyoufeel (всего исправлений: 2)
Ответ на: комментарий от hateyoufeel

В Си нет ничего про ближние/дальние указатели и сегментную модель памяти, которая была в x86

Небыло x86.

Про кеши Си тоже не знает.

Зачем?

Понятие «современный линуксовый софт» это что-то сферичное.

Да нет, это вполне конкретные вещи: софт, работающий под Linux и написанный в последние 10 лет.

Ну я и сказал сферичное.

Сейчас есть концепция «всё – fd»

fd - первая букавка как расшифровывается?

Это гораздо ближе к модели NT с хэндлами.

Ну модель NT в некоторых частях слизана таки с униха.

Вместе с этим, контроль за доступом сместился со статичных юниксовых прав на динамический фреймворк под названием PolicyKit

Нет, не сместился. То что он позволяет больше это хорошо, но это не значит какого-то смещения.

В общем, современный Linux к оригинальному UNIX имеет куда меньше отношения

Всё развивается.

его архитектура куда больше напоминает Windows.

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

Что в принципе не так плохо, потому что Windows NT далеко не самые глупые люди проектировали

Насчет оригинала спорить не буду.

Оно много где есть, но не везде.

Да, в Android его нет, это вообще отдельная экосистема.

Я не про андроид.

anc ★★★★★
()
Ответ на: комментарий от hateyoufeel

В Линукс давно уже нет концепции «всё – файл». Сейчас есть концепция «всё – fd».

Так было и до Linux, общая память, сокеты.

Это гораздо ближе к модели NT с хэндлами.

Там модель с объектами, которая работает иначе, в Windows сокеты не могут обрабатываться с помощью _write, _close.

на дизайн языка Си очень сильно повлиял ассемблер PDP-11.

Да. В Си нет ничего про ближние/дальние указатели и сегментную модель памяти, которая была в x86, например.

Деннис Ритчи писал что свой ассемблер для PDP-11 делали они тоже, поэтому синтаксические конструкции типа *b++ пришли из него действительно, но придумали они их сами. Поэтому влияние не такое сильное как можно предположить.

А если мы возьмём Лисп-машины или, ещё хуже, какой-нибудь iAPX432 с хардварной поддержкой ООП, там Си фактически с другой планеты будет.

В AS/400 есть опкод «создать базу данных». Для С там наверное есть as400.h или набор #pragma, как сделали для аппаратного zlib в POWER. В этом же и суть портабельности, что нету разных типов указателей и команд create_db().

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от alysnix

Ладно. Сформулирую так: в железе нет UB. Реакция на встреченную illegal instruction у процессора строго определена.

Понятие «разрешенной операции» действительно скорее философское.

monk ★★★★★
()
Ответ на: комментарий от alysnix

еще раз говорю. заниматься сишечкой не зная ассемблера, это все равно что резать скальпелем не зная анатомии.

Разве что ассемблер PDP или 8086. Современный ассемблер скорее вредит при изучении Си. Потому что 90% ассемблерных операций изобразить на Си просто не получается.

И даже работа с памятью совершенно другая: в ассемблере если есть переменная длиной 10 байтов, а за ней другая переменная ещё на 10 байтов, то при записи в первую переменную по смещению 11 будет записан первый байт второй переменной. В Си будет что угодно.

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

Ну вот. В процессоре это определённая операция. А в Си может случиться что угодно.

таким образом делается длинная арифметика, например. или проверятся факт переполнения.

В Си не таким. Смотрите исходники GMP, например.

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

И при чём тут питон? При том, что там язык уже поддерживает длинную арифметику, а не требует гарантии от программиста, что знаковое число всегда поместиться в 32 бита?

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

В Линукс давно уже нет концепции «всё – файл». Сейчас есть концепция «всё – fd».

Так было и до Linux, общая память, сокеты.

Да, всё так. Поэтому я и написал выше, что смерть UNIX как идеи началась ещё в 1980х.

Это гораздо ближе к модели NT с хэндлами.

Там модель с объектами, которая работает иначе, в Windows сокеты не могут обрабатываться с помощью _write, _close.

Это уже не так важно. Важно то, что всё в итоге приводится к единой модели вместо зоопарка разных API. Жаль что в Linux это происходит через жопу и, например, signalfd() не покрывает 100% сценариев с сигналами.

на дизайн языка Си очень сильно повлиял ассемблер PDP-11.

Да. В Си нет ничего про ближние/дальние указатели и сегментную модель памяти, которая была в x86, например.

Деннис Ритчи писал что свой ассемблер для PDP-11 делали они тоже, поэтому синтаксические конструкции типа *b++ пришли из него действительно, но придумали они их сами. Поэтому влияние не такое сильное как можно предположить.

Это не так важно, что они *b++ придумали сами. Важно то, что там была плоская модель памяти, что в те времена было не то чтобы частым феноменом.

В AS/400 есть опкод «создать базу данных». Для С там наверное есть as400.h или набор #pragma, как сделали для аппаратного zlib в POWER. В этом же и суть портабельности, что нету разных типов указателей и команд create_db().

Это же можно сделать вообще в любом языке. Что подтверждает тезис, что на сегодняшний день Си является всего лишь ещё одним высокоуровневым языком и никакой близостью к железу не обладает.

hateyoufeel ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

Да, всё так. Поэтому я и написал выше, что смерть UNIX как идеи началась ещё в 1980х.

Ну UNIX и начинался с fd. Не все было отображено файлами.

Это не так важно, что они *b++ придумали сами. Важно то, что там была плоская модель памяти, что в те времена было не то чтобы частым феноменом.

А что еще было на момент создания С? Какие компьютеры имели другую модель?

Это же можно сделать вообще в любом языке. Что подтверждает тезис, что на сегодняшний день Си является всего лишь ещё одним высокоуровневым языком и никакой близостью к железу не обладает.

А раньше он был низкоуровневым, что поменялось с времен PDP?

MOPKOBKA ★★★★★
()
Ответ на: комментарий от hateyoufeel

ты бредишь, дядя… как это пайпами не общается? все там используется. а юникс - это неведомое нечто, обросшее легендами как страна беловодье с кисельными берегами и молочными реками

rtxtxtrx ★★★
()
Ответ на: комментарий от MOPKOBKA

Для удобства компиляторописателей.

luke ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Получается плоская модель в С была выбран не из за влияния PDP, а для удобства?

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

Плоская модель не в Си, а в современных ОС.

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

там не было ситуации выбора

https://www.tuhs.org/

у тя(Кена Томсона) есть регистры и асм(маш код ващет ибо Ken Thompson (Jun 1968). «Programming Techniques: Regular expression search algorithm». Communications of the ACM. 11 (6): 419–422 )

но кошелька(котёнок с дверцей и прочий Петров Python_Ruby Григорий) оперативной памяти (7+-2) не хватат

тут Деня прикатывает агрегацию в наборы struct (не до неймспейсы - ибо смещения были глобальны )

как объявил где структуры можешь после где угодно деалать через точку имя к любому указателю

о какой после такого модели памяти речь ваще?

qulinxao3 ★☆
()
Последнее исправление: qulinxao3 (всего исправлений: 2)
Ответ на: комментарий от monk

Разве плоская модель памяти в стандарте?

Опосредованно.

Насколько я помню, адресная арифметика работает только в пределах одного массива.

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

hateyoufeel ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

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

С чего это? Не надо считать равенство указателей равенством их байтового представления.

monk ★★★★★
()
Ответ на: комментарий от monk

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

С чего это? Не надо считать равенство указателей равенством их байтового представления.

Я не про байтовое представление. Я про то, что могут быть указатели разных типов: с сегментом и без оного. В итоге у тебя ближний указатель никак нельзя будет сравнить с дальним, просто потому что в первом нет инфы о сегменте. Но при этом оба указывают на один и тот же объект.

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

hateyoufeel ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

просто потому что в первом нет инфы о сегменте

В первом сегмент в сегментном регистре. И компилятор знает значение этого сегментного регистра.

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

Операция & должна выдавать один ответ. Поэтому основной тип указателей должен быть один.

При компиляции указатели на текущий сегмент компилятор может сделать ближними. Но это уже оптимизация.

P. S. Так же и было. Модель памяти в 8086 определяла тип указателей. Или все ближние и данные должны уместиться в 64К или все дальние и работает чуть медленнее.

monk ★★★★★
()
Ответ на: комментарий от monk

Операция&должна выдавать один ответ. Поэтому основной тип указателей должен быть один.

Операция & не единственное место, откуда можно указатель получить.

P. S. Так же и было. Модель памяти в 8086 определяла тип указателей. Или все ближние и данные должны уместиться в 64К или все дальние и работает чуть медленнее.

Не, были сишные компиляторы с отдельными far и даже huge pointers, например.

hateyoufeel ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

Операция & не единственное место, откуда можно указатель получить.

Но она определяет, чем указатель является. Всё остальное может иметь свои функции foomalloc, foofree, fooget, fooset и писать хоть в облако.

monk ★★★★★
()
Ответ на: комментарий от hateyoufeel

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

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

То что существовали компиляторы с far расширениями не касается стандарта, и других возможных реализаций.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

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

У тебя есть функция, принимающая указатель, и она находится в отдельной библиотеке. Как коду в функции знать, какой именно указатель ей пришёл (сколько байт), если это не указано специально в типе?

hateyoufeel ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

Просто хранить пару, вторую часть обрезать если можно оптимизацией. Можно еще переключать модель, в intel64 генерируемый код по умолчанию тоже не совсем 64 битный как можно подумать, за это отвечает флаг mcmodel.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Просто хранить пару, вторую часть обрезать если можно оптимизацией.

Пару чего?

Упрощу вопрос: сколько байт со стека забирать на аргумент?

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

Он к размеру указателей отношения не имеет, только к расположению кода и данных в памяти.

hateyoufeel ★★★★★
() автор топика
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Пару чего?

Сегмент + Указатель.

Упрощу вопрос: сколько байт со стека забирать на аргумент?

Ты же понимаешь что это зависит от архитектуры? Я не знаю сколько занимает полный указатель в x86.

Он к размеру указателей отношения не имеет, только к расположению кода и данных в памяти.

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

И так же можно разделить сегменты по принадлежности данных, какая то область только для кода, какая то только для констант, какая то только для изменяемых переменных.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от qulinxao3

Ну с одной стороны был такой ранний компилятор С, а с другой стороны были pipe и текстовые потоки, что не говорит о том что они хотели прям каждый байт экономить.

MOPKOBKA ★★★★★
()
Ответ на: комментарий от hateyoufeel

Про одно, ты знаешь как работал x86? Я не особо, но прекрасно понимаю что можно было использовать большие указатели, которые помимо адреса внутри сегмента хранили еще и сам номер сегмента.

Поэтому ответ на твой вопрос максимально простой, хранить пару: номер сегмента + адрес внутри. Зачем различать указатели в таком случае, если он всегда только большой? Размер ну пускай 3 байта. 1 байт на сегменты, их вроде немного было, и два байта на адрес внутри сегмента.

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

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от monk

Современный ассемблер скорее вредит при изучении Си.

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

Потому что 90% ассемблерных операций изобразить на Си просто не получается.

Их можно легко добиться с хорошим компилятором, таким как gcc, потому что он хорошо распознает намерение и генерирует нужные команды.

Вот прямо вписать lea(rax, rcx) не выйдет, но так ли это нужно в С?

в ассемблере если есть переменная длиной 10 байтов, а за ней другая переменная ещё на 10 байтов, то при записи в первую переменную по смещению 11 будет записан первый байт второй переменной

Неправда, только если ты их расположил в памяти друг за другом, и это можно сделать и в С. Потому что в ассемблере переменная может быть и extern.

Ну вот. В процессоре это определённая операция. А в Си может случиться что угодно.

Если ассемблер не переносится 1 в 1 в С, это еще не значит что он плох.

Давай в противовес я запишу плюс изучения: Можно изучать godbolt, посмотреть во что раскрываются новоизученные выражения.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от hateyoufeel

Да, всё так. Только это не мешает тому факту, что на дизайн языка Си очень сильно повлиял ассемблер PDP-11. А к другим ассемблерам Си относится примерно никак и близости никакой нет.

А что у него вообще от ассемблера PDP-11? Многое С берет из BCPL, до узнаваемости язык формируется в B, который был забыт в пользу C как раз из за новых PDP машин. Проще всего во влияние PDP-11 записать разбиение на стандартные типы char, int, ...

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

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

На ассемблере оперируешь отдельно регистрами, отдельно памятью, явно указываешь векторные операции. В Си это приводит к стилю «как намекнуть компилятору в рамках синтаксиса Си, чтобы он сделал то, что я имею в виду».

потому что он хорошо распознает намерение

Вот это я и подразумевал.

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

Я же написал «а за ней другая переменная». Это и есть «друг за другом».

это можно сделать и в С

А в Си

int f(int x)
{
  int a[10];
  int b[10];
  int c[10];

  if (x > 0) {
    b[11] = 1;
    printf("ok\n");
  }
}

будет UB и f(10) может ничего не вывести.

Если ассемблер не переносится 1 в 1 в С, это еще не значит что он плох.

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

Можно изучать godbolt, посмотреть во что раскрываются новоизученные выражения.

Тогда перед Haskell’ом и лиспом тоже ассемблер изучать? Чтобы смотреть, во что раскрываются замыкания и ленивые списки.

monk ★★★★★
()
Ответ на: комментарий от monk

На ассемблере оперируешь отдельно регистрами, отдельно памятью, явно указываешь векторные операции.

В С отдельно оперируешь стековыми переменными, отдельно памятью, явно можно указать векторные операции. Есть ключевое слово register, можно привязать его к rax.

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

Я же написал «а за ней другая переменная». Это и есть «друг за другом».

Нет, это когда ты определяешь переменную в каком то одном memory layout (не знаю как называется точно), переменная как я уже сказал может быть и extern. В С тоже так можно, задаешь структуру, упаковку.

Еще в ассемблере может быть задано выравнивание переменных, поэтому ничего в следующую переменную тоже не запишется.

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

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

Стандарт же не появился как особое ответвление, он вырос из платформ.

Навыки, полученные в ассемблере, в Си вредят.

Они не могут вредить. Вредить может попытка программировать на %a-lang-name% в %b-lang-name%.

Тогда перед Haskell’ом и лиспом тоже ассемблер изучать? Чтобы смотреть, во что раскрываются замыкания и ленивые списки.

Конечно, и очень желательно еще знать С/C++, на которых от части написаны GHC и SBCL.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от monk

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

да канешно другая семантика.

берем masm и кладем рядом с си, что видим:

тут и там почти идентичные макросы

скалярные типы данных - байты, слова, разной длины, плавающие разной длины

структурные типы - структуры, юнионы.

паблик и экстерн символы

инклуды

константы.

выравнивания и проч.


что там в си осталось кроме горсти операторов-то? это в masm еще изрядно наворотов, которых нет в си, связанных с железом.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

В С отдельно оперируешь стековыми переменными, отдельно памятью, явно можно указать векторные операции. Есть ключевое слово register, можно привязать его к rax.

Компилятор имеет право всё это игнорировать, если считает, что результат не изменится. «Стековая переменная» вполне может быть в регистре или вообще нигде.

Еще в ассемблере может быть задано выравнивание переменных, поэтому ничего в следующую переменную тоже не запишется.

В любом случае переменные - это просто конкретные адреса в памяти. Как и в Форте, например. В Си переменная - это абстракция для компилятора. Можно получить переменные с разными значениями и идентичными «адресами».

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

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

При написании же Сишного кода, смотреть во что он превратится на Элбрусе, Интеле и Мотороле смысла особого нет. Потому что другой компилятор или даже тот же компилятор с другими ключами выдаст совершенно другой код.

Семантика обрезает ассемблерную от разных платформ в рамках переносимости, при этом часто в проекте используется семантика некоторого круга платформ.

Нет ни одной платформы, для которой ассемблер

a:
        .zero   40
find:
        mov     eax, OFFSET FLAT:a
        mov     edx, OFFSET FLAT:a+44
        jmp     .L3
.L8:
        add     rax, 4
        cmp     rdx, rax
        je      .L7
.L3:
        cmp     DWORD PTR [rax], edi
        jne     .L8
        mov     eax, 1
        ret
.L7:
        xor     eax, eax
        ret

возвращал бы 1 для вызова при любом значении rax. А вот семантика Си такое позволяет.

Кого поможет подготовить изучение С только по стандарту, скрывая то на чем он основывается? Комитетчика?

Человека, который будет писать быстрый переносимый код. Без опоры на трактовку UB тем компилятором, которым он собирает, и без издевательства над кодом, чтобы компилятор, которым он собирает, использовал какую-то быструю ассемблерную инструкцию на текущей платформе.

Типа такого:

void swap(int* a, int* b)
{
    *a ^= *b;
    *b ^= *a;
    *a ^= *b;
}

Стандарт же не появился как особое ответвление, он вырос из платформ.

Стандарт позволяет эмулировать семантику близкую к PDP на современных процессорах. Но преобразование в ассемблер сейчас совершенно нелинейное. Может быть цикл в Си и отсутствие переходов в ассемблере, может быть наоборот.

Вредить может попытка программировать на %a-lang-name% в %b-lang-name%.

Я примерно про это и пишу. Если человек верит, что Си близок к ассемблеру, то пишет на Си ужасные вещи. Если изначально относиться к Си как к Хаскелю (некий компилируемый язык, имеющий собственную семантику, не зависящую от ассемблера платформы, в которую компилируется), тогда нормально. Но тогда ассемблер становится бесполезен, так как никакой полезной информации от того, что в данном конкретном случае на данном процессоре конкретный компилятор смог воткнуть операнд предварительной загрузки кэша, а в другом случае смог векторизовать цикл, получить нельзя.

Конечно, и очень желательно еще знать С/C++, на которых от части написаны GHC и SBCL.

Это позволит лучше писать на Хаскеле и Лиспе? Как?

monk ★★★★★
()
Ответ на: комментарий от alysnix

что там в си осталось кроме горсти операторов-то?

С таким подходом и питон от ассемблера не отличается.

скалярные типы данных - байты, слова, разной длины, плавающие разной длины

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

это в masm еще изрядно наворотов, которых нет в си, связанных с железом.

Вот именно. Причём все эти навороты компилятор си использует, но в си они выглядят как совсем другие операции.

monk ★★★★★
()
Ответ на: комментарий от monk

Если человек верит, что Си близок к ассемблеру, то пишет на Си ужасные вещи.

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

Плюс есть возможность заглянуть в godbolt, узнать как работает оптимизатор вообще, будет возможность через gdb понять что происходит если высокоуровневое представление ничего не дает. Будет возможность использовать низкоуровневые профилировщики.

Если изначально относиться к Си как к Хаскелю

Получается будет проигнорировано все, локальность кеша, производительность unsigned арифметики, векторизация. Для многих проектов это уже не подходит, даже вполне себе десктопных.

А для встраиваемых? Там может даже не быть таких хороших оптимизирующих компиляторов как gcc и clang, может быть свой мир с расширениями и кучей ub по стандарту в коде, без которой из компилятора нормально производительности не выжать. Да тут даже о С речь не идет, нужно заполнять значение регистров, писать в память по адресу, это все далеко за пределами стандарта. Нужно хотя бы примерно понимать как оно работает, что есть регистр.

Нельзя настолько отвязывать стандарт от реальности.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от monk

Компилятор имеет право всё это игнорировать, если считает, что результат не изменится. «Стековая переменная» вполне может быть в регистре или вообще нигде.

Есть компиляторы ассемблера в высокоуровневое представление, так что там тоже может быть %)

Типа такого
swap: xor

Ксакепские трюки какие то. Код с int tmp самый лучший.

Стандарт позволяет эмулировать семантику близкую к PDP на современных процессорах.

Тут в треде выяснили что PDP это 16 битный компьютер с сегментами, плавающая точка совсем другая. Я пришел к выводу что С берет корни из BCPL и B, которые были до PDP, а от PDP он скорее всего ничего не получил.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от monk

В Си есть массив, в ассемблере нет.

В FASM и классы на макросах сделали, и типобезопасные вызовы WinAPI. Тебе бы ограничить определение ассемблера. В MASM о котором говорит alysnix, уверен, помимо массивов и структуры есть.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от monk

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

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

В Си есть массив, в ассемблере нет.

в си нет массива. как раз в си применяется чисто железячный способ адресации база+индекс, завернутой в идею, что любой указатель, есть указатель на массив. и если есть указатель p, то невозбранно писать - p[i], несмотря на то, что p не есть «указатель на массив». это чисто асмовая фишка.

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

В Си переменная может не иметь адреса

если переменная в регистре, она адреса не имеет в любом случае. что в си, что в асме.

переменные с одинаковыми адресами могут иметь разные значения.

вот тут не понял. физически разные значения, или логически разные? в силу типизированности в си, значение, лежащее по некоему адресу, интерпретируется с учетом типа. в силу наличия union, в си две переменные(находясь по одному адресу) будут иметь разные значения их типа, но и в асме - то же самое. вы можете с одного адреса читать значения разного типа. например как байт и как float.

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

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

alysnix ★★★
()
Ответ на: комментарий от MOPKOBKA

помимо массивов и структуры есть.

и структуры и юнионы.

alysnix ★★★
()
Ответ на: комментарий от MOPKOBKA

Кстати, BCPL уже к моменту появления С имел репутацию переносимого языка, так что совсем разбиваются аргументы о том что С вопреки распространенным архитектурам того времени привязался к PDP и теперь процессоры/компиляторы/чтотоеще его эмулируют, а сам С не приспособлен для портабельности.

Наоборот, взяли за основу портабельный язык, и улучшили.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от monk

дополню. другое дело, что ассемблеры тогда и сейчас очень разные.

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

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

фаталити C

что

 
b [ i ]   

 i [ b ] 

* ( b + i ) 

буквально одно и тоже ибо благо (в отличии от B) известен тип указателя и следовательно если размер базового типа отличается от слова(старое звучание современного байта - минимального набора бит имеющее отдельный адрес) то индекс домножается(обычно сдвигом ибо байтовыравнивание)

ваще С( как и Golang) это буквально ассемблер общего пересечения абстрактной машины современности ( у Гошки поэтому и прикручены горутины ибо современные машины много"поточны")

см Таненбаум Многоуровневая организация ЭВМ 1979г Мир Москва

:)

[upd] по непосредственно над этим сообщением

асмы были на мини-машинах (чё таже pdp-8 там всего 5 тыс транзисторов :)) простые и на микропроцессарах i4004 но уже z80 укурен

на больших машинах микрокод уже и тогда был см опятже лохмятое 79г издание

qulinxao3 ★☆
()
Последнее исправление: qulinxao3 (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Плюс есть возможность заглянуть в godbolt, узнать как работает оптимизатор вообще, будет возможность через gdb понять что происходит если высокоуровневое представление ничего не дает. Будет возможность использовать низкоуровневые профилировщики.

И тогда нет смысла писать на Си. Если ты точно знаешь, какой ассемблерный код хочешь получить, то лучше его и написать.

Получается будет проигнорировано все, локальность кеша, производительность unsigned арифметики, векторизация. Для многих проектов это уже не подходит, даже вполне себе десктопных.

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

Сейчас даже for(int i; i<count; i++) *to++ = *from++; на современных компиляторах работает быстрее, чем

send(to, from, count)
register char *to, *from;
register count;
{
    register n = (count + 7) / 8;
    if (!count) return;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}

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

Да тут даже о С речь не идет, нужно заполнять значение регистров, писать в память по адресу

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

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Ксакепские трюки какие то. Код с int tmp самый лучший.

Когда-то они ускоряли код, так как xor один такт на регистре, а регистров используется на один меньше.

Тут в треде выяснили что PDP это 16 битный компьютер с сегментами, плавающая точка совсем другая.

Семантика плавающей точки вообще за пределами сишного стандарта. Сегменты также учтены в том, что нельзя прибавить к указателю произвольное число, может быть UB. А для современного компьютера с плоской памятью выглядит как случайное ограничение.

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Тебе бы ограничить определение ассемблера. В MASM о котором говорит alysnix, уверен, помимо массивов и структуры есть.

a:
        .zero   40
find:
        mov     eax, OFFSET FLAT:a
        mov     edx, OFFSET FLAT:a+44
        jmp     .L3
.L8:
        add     rax, 4
        cmp     rdx, rax
        je      .L7
.L3:
        cmp     DWORD PTR [rax], edi
        jne     .L8
        mov     eax, 1
        ret
.L7:
        xor     eax, eax
        ret

Как указать, что a является массивом на 40 байт и чтение за его пределами UB, чтобы этот код всегда возвращал 1?

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

monk ★★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)