2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3  След.
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 00:14 


07/10/15

2400
Dmitriy40 в сообщении #1444062 писал(а):
И если конструкции !!a и a!!

Вроде бы таких не бывает, !a логическое не, ~a побитовое не. По крайней мере я раньше всегда так думал.

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 00:36 
Заслуженный участник


20/08/14
11766
Россия, Москва
Andrey_Kireew в сообщении #1444233 писал(а):
Dmitriy40 в сообщении #1444062 писал(а):
И если конструкции !!a и a!!
Вроде бы таких не бывает, !a логическое не, ~a побитовое не.
Да, это так. Впрочем конструкции !!a и ~~a вполне допустимы языком и первая иногда даже осмысленна (если тип a не булевый, то любые ненулевые значения приводятся к единице), вторая же ничего не делает кроме преобразования типов.
Я подразумевал что можно (было) придумать синонимы для a=!a и a=~a в виде !!a/a!! и ~~a/a~~ полностью аналогично инкременту/декременту, но для a=-a синоним по единым правилам придумать сложнее из-за конфликта с декрементом.

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 01:04 


07/10/15

2400
Понятно

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 02:09 
Заслуженный участник


20/08/14
11766
Россия, Москва
warlock66613 в сообщении #1444064 писал(а):
Это всё из-за отсутствия foreach и смежных концепций. Rust - где foreach есть - избавился от этих монстров (++ и --).
В принципе наверное да, согласен что foreach снимет бОльшую часть вариантов использования инкремента/декремента. Но вот как быть с увеличением счётчика наступивших событий? Он к массивам не привязан. Руками писать cnt+=1? Конечно выход, но cnt++ может быть понятнее. То же самое с счётчиком на уменьшение, например ожидание наступления $n$ событий (или задержка времени циклом). Ну и в выражениях инкремент/декремент (не индексов и не указателей) удобны, даже несмотря на побочные эффекты, ибо сокращают писанину (сравните замену while (--n) {...} на while (n-1) {n-=1; ...}, причём после выхода из цикла n будет иметь разное значение, а эквивалентная замена на n-=1; while (n) {...; n-=1;} длиннее и главное не позволяет пользоваться continue в цикле; добавление после цикла n=0 отличается при использовании break внутри цикла; хорошего красивого и короткого решения я не знаю).

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 03:07 
Заслуженный участник


27/04/09
28128
Dmitriy40 в сообщении #1444249 писал(а):
Руками писать cnt+=1? Конечно выход, но cnt++ может быть понятнее.
А чем оно понятнее? Языков с совмещёнными присваиваниями, но без инкремента/декремента, вроде достаточно много, чтобы знающие их, начав читать сишный код, чуть помедлили, гугля или вспоминая из глубин памяти ++. :-) Синтаксис += обычно аналогичен синтаксису целой кучи других совмещённых присваиваний, а инкремент лишь декременту, и разница постфиксного и префиксного может быть даже менее самоочевидной, а с присваиваниями такого варианта попросту нет.

Dmitriy40 в сообщении #1444249 писал(а):
while (--n) {...}
Ннуу я бы лично не использовал для этого while. В нескольких языках, которые видел, там был бы тот же for[each] по диапазону [n-1,n-2..1] (здесь в хаскельных обозначениях) (и в некоторых оно может компилироваться в обычный фор со счётчиком без дополнительных сущностей).

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 06:53 
Заслуженный участник


20/08/14
11766
Россия, Москва
arseniiv в сообщении #1444253 писал(а):
Ннуу я бы лично не использовал для этого while.
Не все языки поддерживают изменение счётчика цикла внутри самого цикла. В данном случае выбор while может быть обусловлен такой необходимостью (чуть надуманный пример: проход по динамически меняющемуся списку/массиву).
Плюс не уверен что после выхода из цикла foreach останется доступным счётчик цикла (или указатель) для проверки пути выхода из цикла (break или нормальное завершение), это бывает полезно. Да, это решается лишней писаниной с дополнительной переменной, но я не любитель лишней писанины (я даже активно пользуюсь возможностью не ставить {} для одного оператора, в чём ++/--/= сильно помогают).

По поводу понятности. Да, a+=1 более универсально, а a=a+1 ещё более универсально (машина же Тьюринга ещё на порядки универсальнее, кто только для неё пишет код ...), но ведь речь не про универсальность, а про удобство программиста (включающее в себя замену часто используемых конструкций на более простые и короткие). Про недостатки a=a+1 долго говорить не буду, достаточно того что не всегда безопасно и допустимо двойное разыменование. Вариант a+=1 неплох, но в нём есть лишний термин, та самая единица. И ещё могут быть объекты, допускающие инкремент/декремент, но недопускающие модификацию более чем на единицу (не уверен как это в С++, но объекты такие точно бывают, видел примеры где-то в учебниках, например указатели/индексы в связанные списки или какие-то итераторы) и для них операция "+" (и соответственно "+=") не определена, а операция "++" вполне себе определена (как операция взятия следующего значения/объекта). Зато он хорош явным указанием на модификацию переменной (есть знак присваивания). В принципе да, можно ограничиться вариантом a+=1 и не вводить инкремент/декремент, но видимо последние нужны (были) столь часто и столь упрощали код, что показалось удобным их добавить (каноничный пример while (*a++=*b++) ; без операций ++ выливается в лишнюю писанину do { *a=c=*b; a+=1; b+=1;} while (c);, да ещё и с лишней переменной, мрак). Так и операцию "=" можно превратить в оператор, как почти во всех других языках, что тоже увеличивает писанину.

Возвращаясь к вопросу темы почему не добавили много других операций: вот потому и не добавили, что тогда они не были столь же часто нужны. Мне (для МК) постоянно нехватает битовых операций (над одним битом), типа a.3=!b.5 (или даже полей битов, типа a.7-5=b.3-1), причём в некоторых архитектурах они реализованы аппаратно, а программной/языковой поддержки нет. Изредка компилятор столь умный что преобразовывает страшный С-шный код в пару аппаратных команд, но намного чаще наоборот, короткий и удобный С-шный код превращается в такое ... :facepalm: что беру асм и переписываю, и обычно сразу всю функцию. Для mainstream архитектур компиляторы хороши, для менее распространённых (МК в частности) часто ужас-ужас (недавно в прерывании пытался заставить компилятор получить три процессорные команды, выделение младшего бита и вдвиг его в другой регистр и условный переход по выдвинутому биту, больше дня пытался, не получается, код от втрое большего, до десятка раз, плюс одна-две временные переменные, и это в прерывании, где счёт буквально на такты!).

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 12:44 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Dmitriy40 в сообщении #1444249 писал(а):
Ну и в выражениях инкремент/декремент (не индексов и не указателей) удобны, даже несмотря на побочные эффекты, ибо сокращают писанину (сравните замену while (--n) {...} на while (n-1) {n-=1; ...} <...> n-=1; while (n) {...; n-=1;} <...> добавление после цикла n=0...).

Извините, замену while (--n) {...} на while (n-=1) {...}
И все ваши перечисляемые преимущества рассеиваются как дым.

(Более того, можно взять переменную любого типа, раз уж "не индекс и не указатель", и написать while (x-=Delta_x) {...} )

-- 11.03.2020 13:01:57 --

Dmitriy40 в сообщении #1444259 писал(а):
причём в некоторых архитектурах они реализованы аппаратно, а программной/языковой поддержки нет.

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

-- 11.03.2020 13:05:38 --

Dmitriy40 в сообщении #1444259 писал(а):
недавно в прерывании пытался заставить компилятор получить три процессорные команды, выделение младшего бита и вдвиг его в другой регистр и условный переход по выдвинутому биту, больше дня пытался, не получается, код от втрое большего, до десятка раз, плюс одна-две временные переменные, и это в прерывании, где счёт буквально на такты!

Ну, значит, high-level language не для тактов. К тому же, если вы знаете, какие три команды хотите получить, почему бы их и не написать, хотя бы в ассемблерной вставке.

Для вашей ситуации хорошо бы подошли аналоги B/BCPL/C--, неужели их нет?

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 14:19 
Заслуженный участник


02/08/11
7003
Dmitriy40 в сообщении #1444249 писал(а):
сравните замену while (--n) {...} на while (n-1) {n-=1; ...}
Такие трюки красивы и понятно, что жалко их терять. Но, по-моему, без трюков лучше. Так что я бы заменил на прямолинейное (псевдокод) for i in (0 .. n).reverse(). Это гораздо проще и естественее, чем while (--n).

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 16:43 
Заслуженный участник


27/04/09
28128
Dmitriy40 в сообщении #1444259 писал(а):
Плюс не уверен что после выхода из цикла foreach останется доступным счётчик цикла (или указатель) для проверки пути выхода из цикла (break или нормальное завершение), это бывает полезно.
Кажется, в некоторых языках можно было дописать к циклу блок, выполняющийся только при нормальном завершении, или наоборот при раннем, точно не помню. Довольно прозрачное решение, но додумались не сразу. Ещё я полгода-год назад видел великолепное решение, но в другую сторону: exitwhen, решающее заодно и выход из нескольких вложенных циклов (и даже что-то типа break break continue оно позволяет, если засунуть exitwhen внутрь части циклов).

Dmitriy40 в сообщении #1444259 писал(а):
И ещё могут быть объекты, допускающие инкремент/декремент, но недопускающие модификацию более чем на единицу
Ну почему же? x += n можно определить всегда как n-кратный инкремент.

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

-- Ср мар 11, 2020 18:47:47 --

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

-- Ср мар 11, 2020 18:54:08 --

(Оффтоп)

Вообще по-моему в современных языках назрела нужда в алгебраических эффектах (чтобы например пользователь сам мог определить такое continue с параметром), но они в общем случае эквивалентны разделённым продолжениям (в смысле delimited continuations), и потому не любой код можно превратить во что-то достаточно эффективное (как делается для обработки исключений, например; исключения особы тем, что они линейно используют продолжение, а именно вообще никак его не вызывают, и мы не можем его даже предоставить — потому оно никак не поминается в соответствующих конструкциях в языках; но throw — это в сущности конструктор эффекта, а catch — обработчик; и try позволяет снять эффект с кода, навесив обработчик).

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 17:18 
Заслуженный участник


20/08/14
11766
Россия, Москва
Munin в сообщении #1444293 писал(а):
Извините, замену while (--n) {...} на while (n-=1) {...}
И все ваши перечисляемые преимущества рассеиваются как дым.
Хм, действительно, чего-то я стормозил (думал в терминах паскаля где все такие трюки недопустимы). Спасибо.
Munin в сообщении #1444293 писал(а):
В таких ситуациях делают расширения языка (убивающие переносимость, но на неё и не замахиваются...).
Ваши б слова да разработчикам компиляторов в уши ... Эх. Не делают, паразиты. А оптимизаторы не доросли до замены переносимого кода на аппаратно поддерживаемый целевой платформой (тому примеров море, хотя бы для AVR, вроде распространённая архитектура, а компиляторы между ужасны и лишь плохи).
Munin в сообщении #1444293 писал(а):
К тому же, если вы знаете, какие три команды хотите получить, почему бы их и не написать, хотя бы в ассемблерной вставке.
Причин несколько: проблемы с указанием точки перехода (придётся вместо стандартного for() использовать метку и jump, что возможно, но криво), проблемы с получением переменной в регистр (не всегда известен адрес переменной или есть способы его получить), проблемы с указанием компилятору что этот регистр оказывается занят и только в рамках этого куска кода, проблемы с размещением переменной (неясно заранее будет ли она в памяти или регистре, если насильно не положить её в память, что плохо), хотелось бы всё же переносимости исходного кода (потому и мучался с С), остальной код не сильно лучше и поблажка тут предрасположит к переписыванию на асм всей функции (что не есть плохо, но хотелось избежать). Ну, что вспомнил.
После дня борьбы с компилятором остановился на самом приемлимом для меня коде (и С и машинном). И после каждой компиляции приходится смотреть не передумал ли вдруг компилятор и не испортил ли опять этот кусок (ибо были примеры такого поведения).

(Про другие языки и глюки компиляторов)

Munin в сообщении #1444293 писал(а):
Для вашей ситуации хорошо бы подошли аналоги B/BCPL/C--, неужели их нет?
Не знаю. Даже больше скажу, не уверен что есть другие компиляторы С кроме IAR и Keil (Cosmic это кошмар), в данном случае это было семейство STM8. Про другие языки вообще глухо, может и есть, но качество компилятора под большим вопросом. Даже в этих компиляторах (конкретно IAR) встречаются совершенно невообразимые глюки, например год назад был возврат партии изделий из-за ошибочного функционирования, после долгих разбирательств, благо глюк воспроизводился 100%, оказалось компилятор самовольно назначил две разные переменные на один адрес в eeprom, без всяких предупреждений или уведомлений! Узнал лишь после анализа машинного кода в hex файле! Это вообще как называется?! :facepalm: Обе переменные были корректно объявлены и обе использовались, с чего вдруг ему что-то померещилось не представляю. Оказалось эта ситуация, с конкретно этими переменными, и конкретными значениями в них, тестами не покрывалась, хотя по отдельности они проверялись и работали правильно. Хотел отослать код в техподдержку компилятора, но любая модификация кода (с целью упрощения) случайным образом исправляла результат компиляции. Промучавшись ещё пару дней в попытках получить минимальный глючный пример бросил это занятие и плюнул, лишь проверяю машинный код в hex файле (в никаких других файлах глюка не видно!! даже в lst и map!) перед передачей на производство. Понимаете глубину жопы? Нигде глюка не видно кроме бинарной прошивки! Хорошо я разбираюсь в ассемблере и могу понять что означают байты в прошивке, а если нет, как проверять правильность машинного кода? Это риторические вопросы, вопль души, отвечать не нужно.
Предложение заменить МК на более распространённый не проходит, STM8 стоил 20р, ближайший аналог (AVR tiny) стоил около 100р, это существенно.
Переписать всё на асм для уверенности в корректности кода отбрасывается: лень, минус переносимость (она не требовалась 100%, но было желание позже МК сменить), затраты времени, сложность поддержки. Переписать на асме только работу с этими переменными тоже не имеет смысла, она размазана по 10% кода и проблемы полезут лавинообразно (уже ходил по этим граблям).
В общем, как уже говорил выше, для mainstream архитектур всё более-менее неплохо (или даже хорошо), но чуть шаг в сторону (от x86, ARM, AVR, PIC, i51) — и сразу море проблем, для некоторых рассматриваемых мною МК существует ровно один неудобный и глючный компилятор С от производителя МК и всё, без вариантов, даже асма нет.

arseniiv в сообщении #1444341 писал(а):
Ещё я полгода-год назад видел великолепное решение, но в другую сторону: exitwhen, решающее заодно и выход из нескольких вложенных циклов
Да, это похоже красивое и удобное решение одной из проблем. Но как оно реализуемо в уже используемых компиляторах я не знаю. Плюс другие проблемы оно не решает (например модификацию счётчика цикла внутри самого цикла, некоторые языки это запрещают, даже пределы не дают менять внутри цикла).
arseniiv в сообщении #1444341 писал(а):
Ну почему же? x += n можно определить всегда как n-кратный инкремент.
Можно. Возможно поимев проблемы с обработкой исключительных ситуаций (выход за пределы объекта), скоростью, плохой детерминированостью результата (вместо двух исходов возможны n+1 исходы), сложностью контроля переполнения выходных буферов (при инкременте переполнение буфера контролируется на каждой итерации, при n-кратном лишь после добавления в буфер n значений, а они могут быть разной длины и оценить заранее не всегда возможно). Можно, но часто ценой неадекватного увеличения кода. :-(

warlock66613 в сообщении #1444320 писал(а):
Но, по-моему, без трюков лучше.
Наверное тут уже вопрос вкусов. Аргументы есть и за и против. Но с плохим оптимизатором (а он часто очень плох) лучше писать ровно то, что хочешь получить на выходе.

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 17:39 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Dmitriy40 в сообщении #1444346 писал(а):
Ваши б слова да разработчикам компиляторов в уши ... Эх. Не делают, паразиты.

Ну что я вам скажу. В 70-е - 80-е годы люди, очутившись в ситуации типа вашей, садились и писали собственный компилятор. (Часто придумывая собственный язык). Может быть, вам можно договориться с производителем, чтобы получить возможность что-то дописывать в их компилятор, во front-end, или даже написать собственный front-end.

Хотя я понимаю, что не до того, работа масштабная, а денег за неё не заплатят.

Собственный ассемблер можно написать довольно просто и на коленке.

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

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 18:22 
Заслуженный участник


20/08/14
11766
Россия, Москва
Munin
Вы всё правильно говорите. Даже не буду с Вами спорить.

(Лишь пара мыслей вслух.)

На компилятор С моей квалификации пожалуй не хватит, даже на front-end (конечно не попробовав не узнаешь, но всё же). Дело не только в деньгах, скорее во времени. Разработка компилятора займёт реально год(ы), те поделки что я видел, писанные за "пару месяцев по вечерам", это примитивизм, они хуже даже существующего плохого компилятора. Плюс получить внутреннюю документацию (для подстыковки своего front-end) от крупного производителя просто нереально, пробовали, мы не газпром. А часто её вообще нет в оформленном виде! Нормально оформляются лишь публичные документы, остальная информация бывает даже тупо размазана по исходному коду (который вам никто не даст!). Бывает в удобном компиляторе не предусмотрен интерфейс с внешним ассемблером (и линковщиком, да), решается сменой компилятора на неудобный. Внешний ассемблер с подлинковкой obj грохает оптимизацию между процедурами (хотя бы по регистрам). Часто документации от производителя тупо недостаточно для написания ассемблера/дизассемблера (да, в 21 веке!). Бодаться с крупным производителем ... в принципе можно, есть и положительный и отрицательный такой опыт, но практически всегда дешевле (в смысле затраченных ресурсов, в основном времени) плюнуть и сделать как получается. Вы наверное плохо себе представляете закрытость и убогость документации на малораспространённые продукты (например чтобы выяснить отличия китайского клона ARM от оригинала STM32 людям пришлось писать полные тесты состояния до и после для каждой интересующей команды! Похожим делом занимался по необходимости и я лично на работе лет 15 назад для МК семейства i51 от Филипса. Про доки на дешевые Холтеки лучше вообще молчать, там ужас-ужас, а ведь их широко применяют из-за низкой цены и начальство давит на инженеров).

UPD.

(Про асм.)

Я бы с удовольствием писал (да и пишу) на асме, это видно даже по моим сообщениям здесь на форуме. Маленькие проекты (до нескольких страниц С кода) получаются неплохо. Но потом через год-два приходит директор (или менеджер по закупкам) и требует заменить МК на более дешевый совершенно другой архитектуры (регистровый AVR на безрегистровый PIC, к примеру) ... Адаптировать десятки страниц С-шного кода (для среднего проекта), даже с асм вставками, займёт недели, асм код — месяцы (т.к. бОльшая часть кода будет переписана с алгоритма заново). Это бывает критично. Иногда это просто невозможно (прерывания из-за активной работы с памятью не укладываются в период таймера). Но чаще конечно требуют доработать функциональность, на С это в разы проще чем на асме. Потому наличествует противоречие между моими хотелками и требованиями начальства. И приходится идти на компромисс и "грызть тот кактус" с С ... благо эти ужасы всё же не каждый раз. Да, это обычные будни разработчика, я согласен.

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 18:29 
Заслуженный участник


27/04/09
28128
Dmitriy40 в сообщении #1444346 писал(а):
Но как оно реализуемо в уже используемых компиляторах я не знаю.
Вроде никак. Я пока не видел ни одного языка с такой конструкцией, хотя я конечно все их не перебираю.

Dmitriy40 в сообщении #1444346 писал(а):
Возможно поимев проблемы с обработкой исключительных ситуаций (выход за пределы объекта)
Если возможен выход, он возможен и с одинарным инкрементом. :-)

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 18:40 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Dmitriy40 в сообщении #1444352 писал(а):
Вы наверное плохо себе представляете закрытость и убогость документации на малораспространённые продукты

Да нет, немного представляю. И поверьте, тем парням, которые на PDP-8 лабали BCPL и Unix, было не легче :-)

В общем, могу только посочувствовать.

 Профиль  
                  
 
 Re: Инверсия переменной boolean в С/С++
Сообщение11.03.2020, 18:53 
Заслуженный участник


20/08/14
11766
Россия, Москва
Munin
Спасибо.
То было в 70-е, сейчас то прогресс ушёл вперёд. Но не везде. :-(

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 32 ]  На страницу Пред.  1, 2, 3  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group