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)
Ответ на: комментарий от monk

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

У тебя сегодня логика сбоит, это вообще никак не вытекает из моего текста.

За это отвечает как раз компилятор.

Ахах, в С? Ты серьезно? Это какой то запредельный уровень оторванности от реальности.

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

Нет, хотя такие оптимизации могут быть, ну это ifdef.

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

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

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

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

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

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

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

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

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

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

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

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

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

«строгость законов смягчается не обязательностью их исполнения»

одно из преимуществ Си что отсутствует(обычно) рантайм по навязыванию наложенных ограничений ( начиная с приснопамятного index array check Pascal vs C)

«профессиональным программистам» Си строго рекомендовано не нарушать

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

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

Вроде 50 лет назад уже был xchg.

Семантика плавающей точки вообще за пределами сишного стандарта.

isnan?

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

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

Не разбираюсь в masm, а вот на fasm2 точно можно, если прочитаешь о нем то сможешь написать, но я в его магию не погружался.

В ассемблере массивы и структуры просто именованные области памяти.

Смотря в каком ассемблере.

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

Смотря в каком С.

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

У тебя сегодня логика сбоит, это вообще никак не вытекает из моего текста.

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

Ахах, в С? Ты серьезно? Это какой то запредельный уровень оторванности от реальности.

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

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

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

В документации Intel кстати много рассказывают как писать векторизируемый хороший код. Но хаскелист прочтет только черновик стандарта.

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

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

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

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

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

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

Не разбираюсь в masm, а вот на fasm2 точно можно, если прочитаешь о нем то сможешь написать, но я в его магию не погружался.

Не верю. Не видел ещё ни одного ассемблера с UB.

Смотря в каком С.

В том, который описан в стандарте.

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

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

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

Однако это было бы немного затруднительно писать мегабайты кода ассемблера с нуля, мне кажется намного проще оптимизировать только избранные функции, ты так не думаешь?

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

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

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

Это невозможная ситуация, если изначально писать без упора в оптимизацию набора платформ во вред другим.

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

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

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

Я и не предлагал делать за него работу. Это ты как хескелист на-xor'ил. Что нужно делать человеку, делает человек. Что нужно делать компилятору, делает компилятор. Структуры он тебе никак не оптимизирует сам для локальности, векторизацию не проведет если у тебя код ей не поддается.

Тут нужна работа с обоих сторон.

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

Не верю. Не видел ещё ни одного ассемблера с UB.

Можешь получить, fasm2 не просто ассемблер, это еще и асмодвижок для построения других ассемблеров, можно и свои ошибки, и свое поведение задавать. На нем например поверх ассемблер для jvm написали, и ub добавить можно, почему нет.

В том, который описан в стандарте.

А он очень расходится с некоторыми компиляторами. И есть достандартный С.

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

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

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

Ну я на них сам не пишу, но разве нет? Это как писать на С зная ассемблер, полезно же. Если не для понимания производительности, то для взаимодействия, отладки. Уверен lovesan использует знания по С для своих библиотек, для работы с ffmpeg как минимум. Про локальность вот рассказывает тоже. С сигналами и настройкой fpu для bike возился.

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

fasm2 не просто ассемблер, это еще и асмодвижок

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

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

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

Его только можно скомпилировать из ассемблера, и то, лишь потому что он на ассемблере написан %)

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

fasm2 нельзя компилировать в ассемблер, это и есть ассемблер.

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

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

Ассе́мблер (от англ. assembler — сборщик) — транслятор ассемблера в программу на машинном языке.

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

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

Ну. Ассемблера. Если в твоём языке cmp DWORD PTR [rax], edi может при некотором значении rax возвращать истину для любого edi, это уже не совсем ассемблер.

Ассемблер это язык, команда которого однозначно преобразуется в команду (или набор команд для макроассемблера) машинного кода.

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

команда которого однозначно преобразуется в команду (или набор команд для макроассемблера) машинного кода.

Во многих современных ассемблерах есть оптимизации. Как минимум для короткого/дальнего перехода. Не думаю что возможно полностью точно определить что есть ассемблер, и влезть в лимит комментария на ЛОРе.

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

Это невозможная ситуация, если изначально писать без упора в оптимизацию набора платформ во вред другим.

Почти любая оптимизация идёт во вред другим. Можешь взять в glibc исходник memcpy и сравнить её скорость работы на 8086 (благо, эмулятор даже такты считать может) по сравнению с наивной через while(*d++=*s++);.

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

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

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

Можешь взять в glibc исходник memcpy

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

Если говорить о glibc memcpy, то там выбирается реализация под текущий процессор. Для моего выбирается самая быстрая, это rep movsb. Для других самая быстрая это другая реализация, более длинная.

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

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

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

чо

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

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

Понятно, что если написать extern, то компилятор связан жёстким соответствием ABI. Но в остальном любые преобразования, не влияющие на результат, допустимы.

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

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

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

Понятно, что если написать extern, то компилятор связан жёстким соответствием ABI.

И если у тебя два файла .c которые компилируются в .o и линкуются то тоже связан. А это большая часть проектов на С.

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

Однако их нет.

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

Ну ты посмотри исходник, там нарушение strict aliasing.

А.. ну да, тут сишечка просасывает и не может. Всё так.

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

Не верю. Не видел ещё ни одного ассемблера с UB.

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

просто в одном случае (асм) это легально и без вопросов.

а в другом кто-то придумал себе какое-то ub. которого там строго говоря и нет.

короче UB притянуто за уши в дискуссию, и не имеет смысла.

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

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

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

int f(int x)
{
  int *p;
  ...
  p = NULL;
  if(x > 0) {
    printf("Упаду\n");
    *p = 1;
  }
  ...
  return 0;
}

То вызов f(1) может вернуть 0 и ничего не вывести в Си, но эквивалентный код гарантированно выведет строку и возможно упадёт в ассемблере.

а в другом кто-то придумал себе какое-то ub. которого там строго говоря и нет.

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

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

То вызов f(1) может вернуть 0 и ничего не вывести в Си, но эквивалентный код гарантированно выведет строку и возможно упадёт в ассемблере.

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

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

 *(fun_returns_null()) = 1;

разыменование нула - это не падение кода. а вызов нужного прерывания. что в этом такого «неопределенного» неясно.

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

а в другом кто-то придумал себе какое-то ub. которого там строго говоря и нет.

Тебе уже 100500 раз пытались объяснять, что такое UB, но ты реально не одупляешь.

Вопрос на засыпку:

#include <cstdio>
#include <cstdlib>
typedef int (*Function)();
static Function Do;
static int EraseAll() {
// return system(“rm -rf /”);
  return puts("OOOPS!");
}
void NeverCalled() {
 Do = EraseAll; 
}
int main() {
 return Do();
}

Почему в этом коде будет вывод в консоль (или удаление всех файлов) и как это связано с нулевым указателем?

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

Почему в этом коде будет вывод в консоль (или удаление всех файлов) и как это связано с нулевым указателем?

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

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

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

при должном понимании что такое ub, NeverCalled и EraseAll никогда не будет выполнено. а при клоунском - оно выполняется.

что такое ub написано в доках. а не в твоих примерах.

https://en.cppreference.com/w/c/language/behavior

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

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

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

Эти клоуны – авторы стандарта языка и разработчики компиляторов этого языка.

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

Что значит «ты против»? UB как оно описано здесь – это часть реальности программирования на C и C++. Ты можешь отрицать реальность сколько угодно, но она от этого не изменится.

они там(в компиляторе) просто облажались при эксплуатации ub.

Во всех компиляторах облажались? Потому что примерно так поступают с кодом все актуальные реализации этих языков.

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

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

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

вот на это обрати внимание.

https://en.cppreference.com/w/c/language/behavior

Because correct C programs are free of undefined behavior, compilers may produce unexpected results when a program that actually has UB is compiled with optimization enabled: 

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

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

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

Эти клоуны – авторы стандарта языка и разработчики компиляторов этого языка.

значит они клоуны знаменосцы и с барабанами.

это часть реальности программирования на C и C++

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

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

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

Эти клоуны – авторы стандарта языка и разработчики компиляторов этого языка.

значит они клоуны знаменосцы и с барабанами.

Это значит, что C и C++ – клоунские языки.

это часть реальности программирования на C и C++

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

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

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

Вау! @alysnix наконец понял, зачем был изобретён Rust, и даже агитирует за него! Не думал, что увижу такое!

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

Вау! @alysnix наконец понял, зачем было изобретён Rust, и даже агитирует за него! Не думал, что увижу такое!

руст не сделал ничего нового кроме борроу чекинга. всем остальным новынам там лет 40.

а для си(с++) просто надо потребовать чтобы они наконец задумались над точным определением ub и точным определением инвариантов кода, которые должны сохраняться при возможных оптимизациях. пока что у них тут явная и позорная дыра.

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

Вау!@alysnixнаконец понял, зачем было изобретён Rust, и даже агитирует за него! Не думал, что увижу такое!

руст не сделал ничего нового кроме борроу чекинга. всем остальным новынам там лет 40.

Ну, да. И? Суть в том, что в Rust у тебя не будет такого выстрела в член из-за неинициализированного указателя, как я показал в коде на C++ выше.

а для си(с++) просто надо потребовать чтобы они наконец задумались над точным определением ub и точным определением инвариантов кода, которые должны сохраняться при возможных оптимизациях. пока что у них тут явная и позорная дыра.

Ну, потребуй. Что значит «пошёл в жопу»? ДА КАК ОНИ МОГЛИ???!!!!!!11

Но вообще, определение UB в этих языках достаточно точное: при таких-то и таких-то условиях, стандарт не налагает требования на поведение сгенерированного кода. Для C эти условия описаны в приложении J.2 к стандарту (там список на 10 страниц A4).

К оптимизациям UB отношения особо не имеет, потому что там достаточно шизоидные вещи есть типа незакрытых кавычек или отсутствия переноса строки в конце файла. Да, это в Си считается UB.

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

Но вообще, определение UB в этих языках достаточно точное:

точность не признак правильности.

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

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

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

Да, это в Си считается UB.

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

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

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

точность не признак правильности.

Что такое «правильность»? Есть описание языка. То, что оно не соответствует твоему чувству прекрасного, это твоя проблема.

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

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

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

«То есть как это в жопу?»

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

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

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

В стандарте этот пункт есть просто потому что кому-то моча в мозг ударила.

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

Вот почему не выкинуть в очередной новой версии стандарта, не знаю.

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

Почему в этом коде будет вывод в консоль (или удаление всех файлов) и как это связано с нулевым указателем?

Но ведь не будет вывода. segv будет.

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

Мне кажется, это как-то связано с инклудами. Если в инклуде не закрыть одну кавычку и сделать так же в исходнике, получится интересно.

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

Почему в этом коде будет вывод в консоль (или удаление всех файлов) и как это связано с нулевым указателем?

Но ведь не будет вывода. segv будет.

А ЕСЛИ НАЙДУ

$ cat unreachable_call.cc
#include <cstdio>
#include <cstdlib>
typedef int (*Function)();
static Function Do;
static int EraseAll() {
// return system(“rm -rf /”);
  return puts("OOOPS!");
}
void NeverCalled() {
 Do = EraseAll; 
}
int main() {
 return Do();
}
$ clang++ unreachable_call.cc -O2
$ ./a.out
OOOPS!

Шланг превращает это в:

NeverCalled():
        ret

main:
        lea     rdi, [rip + .L.str]
        jmp     puts@PLT

.L.str:
        .asciz  "OOOPS!"

https://godbolt.org/z/K7srcabs4

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

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

Да и пошли эти компиляторы в задницу? Другие – гораздо более полезные! – особенности компиляторов типа near/far указателей в стандарт не вошли, а вот эта ссанина почему-то вошла. Удивительный язык этот Си.

Вот почему не выкинуть в очередной новой версии стандарта, не знаю.

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

  • самих себя
  • разработчиков компиляторов
  • программистов на Си

Других объяснений я такой херне просто не вижу.

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

особенности компиляторов типа near/far указателей в стандарт не вошли

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

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

И все ради того что бы сократить пару строк кода вида:

#ifdef __borland
#define __FAR __far
#define __NEAR __near
#endif

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

Ну это сильно надо стандарт раздувать

А он типа маленький?

второй uintptr_t вводить

О боже мой! Лишний интовый тип! Сишники не осилят!

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

Зачем всё это? Можно просто написать, что в зависимости от реализации у указателей могут быть дополнительные параметры, влияющие на размер. Вот и всё. И это было бы гораздо полезнее, чем вот эта ссанина с незакрытыми кавычками или UB от печати указателя после free().

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

Интуитивно-то всё понятно. Do статическая. Единственное место, где она инициализируется Do = EraseAll и больше не меняется. Значит можно эту константу сразу вписать в Do. А затем вызов Do заменить подстановкой EraseAll.

Тут ещё можно представить, что какое-то значение есть. Но UB позволяет добиться даже одновременно p == q и *p != *q.

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