Pull to refresh
34
Михайлов Алексей Анатольевич@MinimumLaw

Linux Kernel, Bare metal, Embedded developer

13
Subscribers
Send message

Точно точно. Особенно если ты назвал эту функцию "погружение на грубину" и вдруг она зачем-то оказывается почти в центе пустыни. Реверс - он такой.

Сергей, тогда единственный вопрос - а это было озвучено пациенту? При чем вот ровно в таком виде? У меня есть полипы. Который год наблюдаем - не растут. Когда обнаружили был вопрос ко мне - удаляем? Я спросил каковы риски для обоих случаев. И все... Выяснилось, что это мое решение и моя ответственность. А какого решения вы ждете от меня? Я даже не с жалобами пришел - просто скринингом накрыло. Мне жить не мешает. Сказали раз в год проверять - ну проверяю. Было бы сказано "жить с этим - все равно что жить на пороховой бочке - до сих пор не рвануло, но гарантии что прямо сейчас не рванет не даст никто" - да и рассуждать бы не стал.

Ну и чисто технический момент. Хорошо, решил я удалять. И куда? Я примерно представляю себе что мне скажут в государственной поликлинике. Да-да, то самое "вот убьют, тогда и приходите". Т.е. по сути, государственная страховая медицина не считает это состояние настолько опасным, что требуется экстренное вмешательство. А почему тогда негосударственная считает по другому? Опять же - общемировая практика. Хорошо, а примеры можно? Вот так, чтоб четко - обнаружили значит удаляем?

Мне кажется несколько некорректным сравнивать указанные вами сущности. Хотя...

Обычному человеку сложно сравнивать риски закупорки с рисками последствий хирургии. А врачи, в частности авторы, сваливают ее на пациента. У которого нет специальных знаний. Больше чем уверен - если бы доктор четко сказал прямо: "риски ходить с камнем превышают риски от хирургии и ее последствий", то тот же IT'шник легко лег бы под нож. С прививками, конечно, ситуация схожая. И есть множество врачей, которые буквально отговаривают от прививок. Что как минимум порождает уверенность в том, что "даже врачи ни в чем не уверены". А часто рождает уверенность в безусловной вредности прививок. Т.е. по сути да - хотел поспорить, но похоже соглашаюсь...

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

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

Среди пользователей Си есть разные категории. 

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

Мы привыкли к тому, что "в каждой избушке свои погремушки", и то же деление на ноль разные платформы обрабатывают по разному. Дайте даже не идею - дайте один рецепт пяти поварам и получите пять похожих, но разных блюд. Так и у нас - платформы похожи в целом, но различаются в деталях. Местами на эти детали можно наплевать, а местами их приходится учитывать. Более того, в большинстве случаев для нас крайне нежелательно сваливаться в исключения. Для нас не секрет, что набор машинных кодов у них разный, а значит разные и ассемблеры. А язык С для нас - это некоторый "усредненный ассемблер", который переводит написанное на нем в конкретный ассемблер архитектуры по вполне понятным правилам. И да - отпимизация для нас это не про "сделай меньше и быстрее", это про "делай что просят и не делай лишнего".

Фраза "могут реализовать по-разному, но должны реализовать хоть как-то, чтобы соответствовать стандарту" - она сродни привычному новоязу. Или есть четкий набор правил или его нет. Но конкретно нам, по сути, не важно. Для нас не новость, что одни и те же действия на разных платформах выполняются по разному и приводят к разным результатам. Это вполне привычный кактус. За то, уж если я прошу поделить X на X, то в соответствии с базовыми требованиями, теми самыми "делай что просят и не делай лишнего", я ожидаю что компилятор сделает именно это и сильно недоволен, если вдруг этого не случается. Мало ли зачем это может понадобится? В конце-концов набившее оскомину "xor x,x" или ее налог на С "x ^= x" вместо "ч = 0" не менее странная конструкция с точки зрения математики. И тем не менее она вполне себе применяется. И на это есть причины.

Программа, использующая UB, не является программой на языке Си. 

Сильное заявление. Но не правильное.

Если моя программа использует UB - она не перестает быть написанной на языке С. Она перестает быть переносимой. Нужна ли мне переносимость - зависит от множества факторов.

Но, именно для меня, она обычно важна в части переносимости между компиляторами (Keil, IAR, GCC), но не важна в части переносимости между платформами. Обычно я не хочу использовать код под Arm на AVR или наоборот. Зато есть желание писать код в коммерческих системах (Keil, IAR), но при этом иметь возможность собирать его рабочую версию Open Source инструментами (gcc). Потому UB (а вернее, как верно подсказали выше - platform specific realisation) - мне не страшно. Конечно, что при условии что все производители компиляторов его понимают одинаково.

Смотрите мой комментарий выше. Увы, но и без ключей, и с -O0 результат константа.

 А лучше с ветряными мельницами вообще не бороться.

Человек который почувствовал ветер перемен должен строить не щит от ветра а ветряную мельницу (с)

Я не борюсь с ветряными мельницами. Я просто вижу естественное развитие языка. Как бы ни казалось адептам других богов, язык С продолжает развиваться. А тот факт, что его развитие не всегда идет в ногу с моими требованиями... Ну и ладно. Мне, в принципе, понятны механизмы которыми я могу добиваться нужного результата. Тут и ассемблерные вставки, и функции непосредственно на ассемблере, и набившая оскомину volatile, и разные ключи компиляции для разных файлов проекта, и #pragma и много чего еще. Что-то переносимо между реализациями, что-то нет. Абсолютно ничего страшного. А весь мой спич исключительно по теме, заданной автором.

Я прекрасно понимаю ПОЧЕМУ оптимизатор так сделал. Ровно так же понимаю почему при оптимизации под минимальный размер он агрессивно выискивает что бы вынести в функцию. Почему при оптимизации на скорость меняется порядок присвоений. Опять же - мне, для моих частных задач, часть решений кажутся спорными. Но мои задачи очень частные. Даже с позиции "железяного" использования языка. И да, опыт позволяет находить и исправлять их достаточно быстро.

Что до конкретного примера автора - то для учебных целей было бы куда полезнее конструкции типа a=x/(x-1), а еще лучше a=x/(x-y). У них не было бы таких проблем, и к реальности они были бы сильно ближе. Но, при всем при этом, мне бы очень хотелось, чтобы с -O0 (или ее аналогами) компилятор четко выполнял пожелания автора и ни на шаг не отступал то того, что написано в программе. Как по мне, вполне справедливая хотелка. Но только она и ничего больше.

Согласен, не самая правильная формулировка. Но...

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

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

И я серьезно не понимаю чем позиция автора "не железячная". Впрочем, я свое видение того, как это стоило бы показать детям приводил. (x/x) действительно очень плохой пример. Во всех смыслах этого слова. И даже безотносительно языка программирования.

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

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

int a,b,c,d;
...
  c = a/b;
  d = a%b;

вполне очевиден. В отличии от операций с вещественными числами.

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

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

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

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

P.S.

Впрочем, доля правды есть. На С переносимо очень сложно поймать overflow/underflow. И не только это. И тут да - не все хотелки можно.

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

Интересно. А я думал, что мне, embedder'щику, деньги платят ровно за это. И язык С создавался как "переносимый ассемблер"... Я бы позволил такие вольности плюсам. Они, обычно, сильно дальше от аппаратуры. Но классическому, безплюсовому С... Это уже перебор.

Проверьте, если GCC под них собирать умеет.

Прямо сейчас в доступе нет. Да и специфика тамошней аппаратуры накладывает некоторые ограничения на использование scanf/printf. Но при случае проверю. Не забуду - отпишусь с результатами.

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

Т.е. все таки цензура. Вариант "потому, что могу" не катит. Малоли что ты можешь - высший разум считает что не нужно.

Тогда и выражайте свои намерения явно, x = 255?

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

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

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

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

Я не против, чтоб деление или умножение на 2^n заменяли сдвигом - все в рамках. Но если я пишу x/x то это означает именно то, что мне НЕОБХОДИМО поделить x на x. И я, как автор, понимаю как это будет работать на конкретной аппаратуре. И ожидаю вполне конкретный выхлоп от компилятора и реакцию оборудования. Я не нарушаю ни правила для оборудования, ни правила формальной системы. С чего вдруг не делается то, что нужно мне как автору?

То же про volatile - к сожалению очень часто приходится пользоваться этим указанием там, где оно не должно стоять в принципе. Это приводит к крайне плохому стилю написания кода, когда оное указание ставится "на всякий случай". Что в корне неправильно.

Либо берете в руки asm.

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

Впрочем, SUN еще в далеком 2008-ом с гордостью рассказывала о том, что мы теперь оптимизируем и ассемблерные вставки. Мы лучше знаем - у нас есть контекст окружения. А недовольны - используйте volatile asm {}; Так что лучше отдельным файлом.

Ну да - та самая детская уверенность. Мы лучше взрослых все знаем... И взрослая улыбка в ответ: "Ок! Действуй! Пока сам шишек не набъешь все равно не поймешь". Так что пусть не страдает. Страдать будет позже, когда подрастет.

Дайте ссылку на компилятор Rust для PIC и AVR. А еще для AIX, beOs, OS/2 и MSDOS (а еще Windows 3.1, QnX и прочего зооларка и бестиария возможных осей и архитектур).

Нет, он не умер молодым. Но в лучшем случае детский сад с отличием закончил. А доживет ли хотя бы зрелости - это мы еще посмотрим.

Да я и не отрицал этого.

А это, на самом деле, очень спорный вопрос. Дело компилятора транслировать код в язык аппаратуры. И если автор желает делить на ноль - на здоровье. Дели. И уже аппаратура будет решать что делать. А решить она может по разному. Например 8051 выставит флаги и (сюрприз!) неопределенный результат (который обычно 0xFF, но это не точно). АVR и PIC даже флагами не пошевелят, правда выставят 0xFF. ARM кинет исключение. Собственно это и есть причина, по которой в С это UB.

И не дело компилятора додумывать что я, как автор, хочу в данном месте. Может мне надо таким вот образом 0xFF в регистры на AVR поместить. Или флажки выставить на PIC. Или принудительно в исключение свалиться. Я автор - мне решать. А компилятор... Может помочь - замечательно. Но мешать не надо.

Да что вы прицепились к стандарту языка, которому уже много лет. Он пережил разный endian, разную разрядность и много чего еще. Все его UB просто следствие необходимости работы в очень разном окружении, которое не ограничивается Linux на amd64/arm64. Проблема не в стандарте. Проблема в избыточной оптимизации, ломающей логику работы. А подобные проблему будут у абсолютно любого языка, когда он достигнет зрелости. Только вот... Большинство умирает молодыми и просто не доживут до этой прекрасной поры. Ну устаю повторять про python при переходе со 2-ой на 3-ю версию. Он уже поломался. В отличии от дряхлого старичка, который держится.

Впрочем - ну его нафиг. Я не буду ввязываться в очередной раз в эти войны. Вообще учить детей сегодня С или плюсам - ну так себе идея. Сюда надо ЗАХОТЕТЬ погрузиться. Это очень специфические языки для очень специфических задач. Это не то, с чем есть шанс случайно встретиться. Удел инженеров. С старом смысле этого слова.

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

Впрочем, это порождает "проблему вагонетки" в мире кода - что лучше, выдать неверный результат на определенной итерации или упасть и прекратить дальнейшую работу совсем. Плохо только, что вот такими скрытыми оптимизациями решает ту дилемму не разработчик (который должен был бы проверить на ноль, если не сразу то после N-ого падения). От него-то как раз проблему спрятали и сильно усложнили отладку. Хорошо когда результат вот так запросто воспроизводится. А если вычисляется? Да из множества переменных? Впрочем, в таком варианте этой проблемы вроде бы и возникнуть не должно.

Где-то мир свернул не туда. Иногда очень хочется вернуться к славному ассемблеру, где только ты был автором.

Проверил для "младшего брата"
#include <stdio.h>

int x;

void main(void)
{
    scanf("%d",&x);
    printf("%d\n", x/x);
}

константа в коде. Четко как в статье. gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0

0000000000001169 <main>:
    1169:       f3 0f 1e fa             endbr64
    116d:       55                      push   %rbp
    116e:       48 89 e5                mov    %rsp,%rbp
    1171:       48 8d 05 9c 2e 00 00    lea    0x2e9c(%rip),%rax        # 4014 <x>
    1178:       48 89 c6                mov    %rax,%rsi
    117b:       48 8d 05 82 0e 00 00    lea    0xe82(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1182:       48 89 c7                mov    %rax,%rdi
    1185:       b8 00 00 00 00          mov    $0x0,%eax
    118a:       e8 e1 fe ff ff          call   1070 <__isoc99_scanf@plt>
    118f:       be 01 00 00 00          mov    $0x1,%esi
    1194:       48 8d 05 6c 0e 00 00    lea    0xe6c(%rip),%rax        # 2007 <_IO_stdin_used+0x7>
    119b:       48 89 c7                mov    %rax,%rdi
    119e:       b8 00 00 00 00          mov    $0x0,%eax
    11a3:       e8 b8 fe ff ff          call   1060 <printf@plt>
    11a8:       90                      nop
    11a9:       5d                      pop    %rbp
    11aa:       c3                      ret

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

И да, для учебного примера куда лучше сгодился бы вариант

#include <stdio.h>

int x;

void main(void)
{
    scanf("%d",&x);
    printf("%d\n", x/(x-1));
}

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

... а в не идеальном, к сожалению, по другому просто невозможно. И это ровно то, на чем всех ловят, и на чем основано 99% методов "социальной инженерии".

1
23 ...

Information

Rating
5,692-nd
Location
Пушкин, Санкт-Петербург и область, Россия
Date of birth
Registered
Activity

Specialization

Инженер встраиваемых систем, Архитектор программного обеспечения
Старший
From 350,000 ₽