Каким должен быть язык программирования? Анализ и критика Описание языка Компилятор
Отечественные разработки Cтатьи на компьютерные темы Компьютерный юмор Новости и прочее

Так ли нужны операции «&&», «||» и «^^»?

В Си-подобных языках принято различать «&&» и «&», «||» и «|», «^^» и «^» («и», «или» и «исключающее или»). Логические операции используют двойные «&&», «||» и «^^», побитовые операции — одинарные.
Причина — в отсутствии полноценного логического типа в родоначальнике этой ветви языков — в языке Си. Остальные языки просто копировали эту «особенность». В Си значение «ложь» — это «0», всё остальное — «истина».

        Возьмём, например, два целых числа, шестнадцатиричные значение которых равно «00000001» и «10000000». Применив к ним логичкую операцию «&&», получаем «истина» && «истина» = «истина». Но применив к ним побитовую «&», получаем: «00000001» & «10000000» = «00000000». Видим, что эти операции не эквивалентны.

        Похоже, что разное обозначение родственных операций всех устраивает. А зря. Если существует логический тип, у которого «ложь» — это «0», а «истина» — не «0» (~0 == 0xFFFFFF, т.е. «-1» в дополнительном коде), то побитовые «и», «или» и «исключающее или» являются и логическими одновременно. Экономия оперций налицо:

int      I, J, K;
         I = 0x00FF0077;
         J = I & 0x11223344;      // результат: 0x00220044
         K = J | 0x00110022;      // результат: 0x00330066
boolean  X = true;
boolean  Y = false;
boolean  Z = X & Y;               // результат: ложь
if ( Z ^ X)                       // результат: истина
        Если сделать так, что оператор «if» принимает только тип boolean, то запись вида «if X=Y» становится незаконной для X и Y любых типов, кроме boolean. Чтобы быть правильной, необходимо делать преобразование к boolean: «if boolean(X=Y)». Это удлинняет запись, но делает очевидными намерения программиста:
int  a, b;
// ...
if (a == b)              // нормально
if (a = b)               // ошибка, если а — не типа boolean
if ((boolean) a = b)     // требуется преобразование к типу boolean
        В логических операций «И» и «ИЛИ» существует один подвох. Дело в том, что они участвуют в ленивых вычислениях. В отличие от побитовых операций. Если первый операнд в операции «И» имеет значение «ложь», а первый операнд операции «ИЛИ» — «истина», то дальнейшие вычисления не производятся. Потому что они бесполезны и уже не могут изменить результата. Но побитовым операциям для вычисления результата второй операнд нужен всегда.

        Но и это не всё. В C++ вычисление второго операнда для логических операций «И» и «ИЛИ» не производится только для предопределённых типов. Для классов, в которых этих операции переопределены, ленивые вычисления невозможны. Почему? Да потому, что в языке не существует средств, которыми бы можно было описать, который операнд ленивый, а который нет.

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

        Но может не всё так трагично, как на первый взгляд? Ведь логические «И» и «ИЛИ» должны, по идее, существовать только для логического типа. Ну может ещё для типов (классов), которые унаследованы от логического Для остальных типов они должны быть побитовыми. Поэтому возможность откладывания вычисления второго операнда нужно оставить только логичесому типу. И типам, для которых логический тип — базовый. Хотя целесообразность создания типов, производных от логического, не очевидна.

        Так что семь раз отмерь, и только один отрежь...

Опубликовано: 2012.09.25, последняя правка: 2021.10.20    22:11

ОценитеОценки посетителей
   █████████████████████████████ 24 (68.5%)
   █████ 4 (11.4%)
   ██ 1 (2.85%)
   ████████ 6 (17.1%)

Отзывы

     2013/11/16 13:05, Noname          # 

В Форт нет логических && !! ^^ а есть только обычные AND OR XOR
а также False = 0, а True = все остальные значения

     2014/01/16 10:56, Pensulo          # 

Позвольте уточнить и дополнить вас, уважаемый Noname.

В современном стандарте Форт аргументы типа flag (содержащие логическое значение) возвращаемые стандартными словами языка в качестве FALSE должны возвращать одноячеечное число со всеми битами сброшенными в 0, а в качестве TRUE должны возвращать одноячеечное число со всеми битами взведёнными в 1. Так что в знаковом трактовании числа выходит что FALSE = 0, а TRUE = -1.
На практике же, повальное большинство слов принимающих аргумент, расцениваемый как логический (не обязательно типа flag, кстати говоря), проводят анализ на равенство именно FALSE и принимают решения исходя из результата этого сравнения, а потому все прочие числовые значения автоматически воспринимаются равными TRUE.

Но суть вашего сообщения в корне верна, — в Форт нет логических операций AND, OR, XOR, а также операция сравнения "=" всегда расценивает свои аргументы как числовые, а не логические.

     2014/03/18 17:37, Noname          # 

Слова ветвления IF WHILE UNTIL сравнивают аргумент на неравенство нулю и "ответвляются" по данному положению вещей. Пэтому де факто True все ненулевые значения. Хотя слова сравнения = <> и др. возвращают True = -1

     2014/05/23 08:00, Pensulo          # 

Слова ветвления IF WHILE UNTIL сравнивают аргумент на неравенство нулю и "ответвляются" по данному положению вещей.

На деле, при дизассемблировании Форт-кода использующего IF, WHILE и UNTIL, можно видеть что сравнение при ветвлении производится как-раз таки на равенство НУЛЮ.

Поэтому де факто True все ненулевые значения. Хотя слова сравнения = <> и др. возвращают True = -1.

Для операторов ветвления — согласен, так и есть. Но, например, выражение "1 2 AND" даст в результате 0, хотя и 1 и 2 по сути являют собою ненулевые значения (т.е. могут расцениваться как логическое True). То же самое относится и к операторам сравнения = и <>, ибо, как я уже заметил ранее, в Форт нет логических (булевых) операций. Все (ну или почти все) операции рассматривают свои аргументы как сугубо числовые значения. И потому надо проявлять особую осторожность при составлении выражений смешанного типа.

     2014/11/04 05:50, Smart          # 

Оператора ^^ в C\C++ нет, как ни странно. Есть только ^.

Как по мне, запись стоˊит унифицировать, но для логических операций предусмотреть "ленивую" и "неленивую" версии. В C это не предусмотрено, в Паскале поведение логических операторов задаётся опциями компилятора, что неудобно. Самый лучший вариант был в VB.NET: в довесок к "ленивым" And и Or имелись "неленивые" AndAlso и OrElse. То же самое можно предусмотреть и здесь: например &, ! -- неленивые операторы (как для целочисленных, так и для логических величин), а &&, !! -- ленивые (только для логических), или наоборот.

     2014/11/04 10:33, Автор сайта          # 

Оператора ^^ в C\C++ нет, как ни странно. Есть только ^.

Я тоже этому удивлялся.

Мне хотелось бы, чтобы все логические операции были «ленивыми». Разница между «ленивыми» и «неленивыми» вычислениями проявляется тогда, когда функция, возвращающая результат, не является чистой, т.е. производит побочные эффекты. Допустим, f(x) возвращает логическое значение и производит побочные эффекты. Тогда
bool a = false; if (a & f(x)) // . . .
Если «&» — ленива, то f(x) не будет вызвана и не произведёт побочный эффект. Поэтому правильно было бы
bool a = false; bool b = f(x); if (a & b) // . . .
Для упрощения языка я бы всё-таки оставил бы только одинарные «&», «|» и «^», сделав их ленивыми.

     2014/11/07 14:08, Сергей          # 

Оператор ^^ не может иметь ленивых аргументов.

     2014/11/10 19:33, Автор сайта          # 

Ну да, конечно.

     2016/06/22 04:19, rst256          # 

Для упрощения языка я бы всё-таки оставил бы только одинарные «&», «!» и «^», сделав их ленивыми. Программиста, не знающего какие функции у него производят побочные эффекты, все равно уже ничто не спасет. А вот насчет замены операций на побитовые я бы не советовал, будет очень весело, если вдруг туда будет записано неверное значение. Да и как насчет битовых полей и типов меньшего размера? Может

если(а ! б) — логическое
если(а ! б > 0х558) — побитовое
.

     2016/06/22 04:40, rst256          # 

Если сделать так, что оператор «if» принимает только тип boolean, то запись вида «if X=Y» — это что — присваивание или сравнение? Для присвоения вполне допустимо применить неявное приведение к логическому типу (по стандарту Си), ведь неоднозначных операций тут нет. Хотя с таким "нестандартным" значением для true это может быть не лишним. А проверка на равенство по определению должна возвращать значение логического типа, а её аргументами могут быть все типы для которых она определена.

     2016/06/22 14:05, Автор сайта          # 

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

Осутствие автоматического приведения целых типов к логическому убережёт от неправильного понимания «if X=Y». Если Y — целое, то правильным будет «if bool(X=Y)». Значение «true» — это всегда -1, т.е. инверсия нуля («false») устанавливает все биты в «1». А инверсия -1 («true») будет равна 0. Явное приведение целых типов с ненулевым значением к логическому типу даст -1, т.е. «true». Если «false» — это 0, а «true» — это -1, то логические и побитовые операции имеют одинаковую аппаратную реализацию. Несовпадение разрядности приводит к неявному приведению к «наибольшему» типу.

     2016/07/14 10:03, alextretyak          # 

Оператора ^^ в C\C++ нет, как ни странно. Есть только ^.

Я тоже этому удивлялся.

Вообще-то такой оператор есть. :)
Называется: !=
И для булевых типов работает также как ^.
Предполагаю, что авторы языков (Си и его производных) предусмотрительно не стали вводить оператор ^^ с абсолютно таким же действием, как у уже имеющегося оператора.

     2016/07/15 17:25, Автор сайта          # 

Видите ли, в Си есть привычка использовать переменные числового типа как логического: 0 — это «ложь», всё остальное — это «истина». Для числовых типов операция «!=» не эквивалентна гипотетической «^^»:
int a = 1; int b = 2;
a != b // «истина»
a ^^ b // «ложь», т.к. a — «истина» (a=1) и b — «истина» (b=2)
a && b // проверяем: здесь «истина», т.к. a и b тоже «истина»

     2016/07/16 09:50, alextretyak          # 

Ну да, верно, про такой "вариант использования" оператора ^^ я что-то не подумал. ☺
Но, вообще-то говоря, несмотря на кажущееся удобство (не нужно писать "лишнюю" проверку != 0), я считаю такое неявное приведение [int к bool] всё же недопустимым (как и сделано в Rust — там оператор if требует значение строго типа bool).

     2016/07/16 14:48, Автор сайта          # 

Я тоже так считаю. Должно быть явное приведение.

     2016/10/31 03:51, rst256          # 

Отсутствие автоматического приведения целых типов к логическому убережёт от неправильного понимания «if X=Y». Если Y — целое, то правильным будет «if bool(X=Y)».

У меня только один вопрос остается: явное приведение логического типа к логическому же типу (ну так сказать тоже для большей очевидности намерений) будет возможно, т.е. "bool b; ... if bool(b)"?

     2017/01/06 23:48, Автор сайта          # 

На этот счёт такие мысли. В языках со статической типизацией (мы ведь о таком языке размышляем, исходя из философии?) типы известны во время компиляции. Следовательно, компилятор должен обнаружить приведение логического типа к логическому. Это бессмысленная с точки зрения компилятора операция. Она должна быть ликвидирована при оптимизации. В принципе, такие операции можно даже запретить. Тогда программист, увидев ошибку при компиляции А=bool(А), понимает, что масло и так масляное. По идее, стремление программиста перестраховаться операциями типа А=bool(А) говорит о том, что он не может почерпнуть информацию о типе у компилятора, он слишком молчалив. Хорошо бы при компиляции иметь не только исполняемый модуль, но и обзор всех внутренностей программы с подробностями, степень которых можно регулировать.

     2018/11/18 15:26, Freeman          # 

Этюд о битовых и логических операциях недавно восстановлен, став теперь частью документации: «Логические и битовые операции ». Раздельные операции нужны для избавления от скобок.

Ленивость вычислений в Канторе не проблема, в языке с объектами первого класса все операции обобщенные.

     2018/11/26 14:23, Автор сайта          # 

Сперва хотел просто ответить, потом хотел доработать статью. В итоге родилась новая статья: «Изменение приоритетов операций».

     2021/03/28 00:12, Виталий Монастырский          # 

О! Теперь я понял — почему у Вас вызывают такие проблемы всякие там операторы равно и двойного &&. Вы просто не понимаете разницы между этими вещами. То есть, для Вас логические операции и логические операторы — это одно и то же. Для того, чтобы разобраться чем они отличаются, нужно понимать их работу на аппаратном уровне. Как только Вы это поймете, у Вас сразу же все проблемы по этому поводу отпадут сами собой и Вы перестанете видеть на ровном месте сферическую проблему в вакууме.

Логические операторы — сравнивают значения, а логические операции, их лучше ещё называть битовыми, чтобы не блудить в трех соснах — это всего-лишь навсего двоичная однобитовая арифметика. То есть, если true and true = true, то 1000 and 0001 — это никак не false, это именно = 0. Ноль, а не false. Вы просто вычли число из нуля, по сути. То есть, в десятичном представлении это аналогично тому, как если бы Вы пытались сравнить true and true = true с 12 — 12 = 0, и удивлялись тому, что здесь что-то не то.

Логика отдельно, математика отдельно. Битовые операции — это всего-лишь двоичная арифметика, которая отличается от логики ка небо от земли... и лишь обозначение операторов вносит смущение в Ваш разум.

Вот реально представьте себе, что одно — это учебник "Формальной логики", а другое — учебник "Арифметики". Вот и всё.

Как я уже писал, чтобы это лучше различать, для логики разумнее использовать операторы в виде слов — or, xor, and, not, а для побитовой арифметики знаки — &, |, ^, ~. И все дела. В речи для логики применять или, и, не..., а для битовых операций — сумма, разность, умножение, инверсия. Ну, Вы поняли, я думаю. Тогда не заблудитесь. Опять таки добра и самопросвещения!

     2021/03/28 00:57, Автор сайта          # 

О! Теперь я понял

Вы как раз то не поняли. Если Вы с чем-то не согласны, то не стоит чужому мнению приписывать некомпетентность. Это очень лёгкое объяснение. Если бы я пошёл по такому лёгкому пути, то предъявил бы сейчас миру кучу Вашу орфографических и синтаксических ошибок в Ваших сообщениях. А потом бы мог поставить знак равенства между Вашими знаниями в области естественных и искусственных языков.

По теме: я лишь захотел съэкономить на знаках операций. К этому имеются предпосылки в языках со статической типизацией. Если в языке логический тип отличен от целого, если нет автоматического приведения целого к логическому (например, в Си
if (0)
ноль автоматически приводится к логическому типу и равен false), то возможна перегрузка операций «и», «или», «исключающее или». Эти операции, будучи применёнными к значениям логического типа, выполняли бы логические операции. При применении к значениям целого типа, они бы выполняли побитовые операции.

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

     2021/03/28 10:46, Виталий Монастырский          # 

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

НО! Раз Вы занимаетесь разработкой языка, то надо бы как-то по-другому подойти к организации сайта. Если Вы по какому-то вопросу решили сменить свою позицию, то несоответствующие идеи должны перемещаться в архив или каким-либо явным образом помечаться "БОЛЕЕ НЕ АКТУАЛЬНО" или "ИДЕЯ ОТКЛОНЕНА", чтобы вновь прибывающим на Ваш пароход было понятно — на каком этапе у Вас проект, к чему пришли, а что осталось.

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

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

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

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

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

Вот такое у меня предложение.

     2021/03/28 19:46, Автор сайта          # 

В языке Ада целый и логический типы не приводятся автоматически друг к другу. В таком случае можно было бы сделать так:
bool a, b, c
. . .
c = a & b // логическая операция "и"
int x, y, z
. . .
z = x & y // побитовая операция "и"
Надо было сразу проиллюстрировать таким примером.

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

     2021/03/28 22:31, Виталий Монастырский          # 

За желанием предельно сократить количество элементов синтаксиса, Вы напрочь забываете про принцип читабельности кода. Вместо
a&b <= c^d or a&c > b|d and a&d != b&c
Вы получите
a&b <= c^d | a&c > b|d & a&d != b&c
и сиди ломай глаза — где тут что и что к чему... А смысл? Ради потери 4 зарезервированных слов для логики? Сокращение базовых элементов языка должно быть разумным — не в нарушение других принципов языка.

     2023/01/04 11:54, kt          # 

Недавно для себя открыл, что в JavaScript, оказывается, есть оператор "===" (сравнение с запретом преобразования типов). Но ведь это открывает безграничный простор для дальнейшего расширения)) Например, "====" — сравнение с запретом преобразования типов и запретом выдачи предупреждения в этом месте. Поскольку одинаковых знаков много, можно ввести коэффициент повторения (как в строках PL/1), т.е. вместо ==== писать =(4)

Кто сказал "глупо и непонятно" ? Тьфу на вас! Так все современные языки устроены ))

     2023/01/04 13:02, Автор сайта          # 

Да, в PHP тоже есть «===», означающая проверку на полное тождество. Ещё можно вспомнить операции циклического сдвига в языке D. Если при обычном сдвиге часть битов исчезают
число << 4;	// исчезают 4 левых бита
число >> 7; // исчезают 7 правых битов
то при циклическом сдвиге биты не исчезают, а появляются с обратной стороны
число <<< 4;	// «вращение» на 4 бита влево
число >>> 7; // «вращение» на 7 битов вправо
Ваша ирония вполне понятна. Но с другой стороны, как ещё обозначить проверку тождества и циклические сдвиги? Можно, конечно, какой-нибудь функцией с традиционным именем типа «is identical». Но существует стиль языка Си, который Евгений Александрович Зуев метко назвал «птичьим»: в нём свист вместо слов. И тем, кто привык к этому стилю, в котором есть своеобразное очарование, легко запомнить новые обозначения с дополнительным символом: «+=», «*=», «&&» и т. д. Языки этого стиля, если просуммировать их общую долю в рейтингах, захватили абсолютное большинство: Си, C++, Java. C#, Javascript, Котлин, Go, Rust, D, Swift, Objective-C, PHP, Perl, Lua, Dart. Так что Вы правы:

Так все современные языки устроены

Один знакомый начинающий программист, который изучал PHP, однажды увидел текст на Javascript: «О, да тут всё почти одинаково!»

     2023/01/04 13:05, Gudleifr          # 

Например, "====" — сравнение с запретом преобразования типов и запретом выдачи предупреждения в этом месте

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

     2023/01/04 13:27, Бурановский дедушка          # 

Один знакомый начинающий программист, который изучал PHP, однажды увидел текст на Javascript: «О, да тут всё почти одинаково!»

Анекдот времён СССР:

Прочитал газету «Правда» и узнал, что написано в остальных газетах.

     2023/01/04 15:07, kt          # 

Поскольку в x86 всего есть 4 типа сдвигов (например, влево): SHL/SAL/ROL/RCL, то по такой логике к операторам «<<» и «<<<» нужны ещё операторы «<<<<» и «<<<<<» )) Если чуть серьезнее, то мне не нравится именно повторение одинаковых символов. В этом смысле, на мой взгляд, "+=" вполне допустим, здесь символы не одинаковые. За годы практики, конечно, у меня составилось собственное видение «как надо» поступать в подобных случаях, например:
  • Сдвиг всегда только один — циклический, если биты нужно выбросить — применяю дополнительно логическое умножение на маску.
  • && — не требуется. Если нужно обязательно вычислить все выражения условия, то именно в этом случае сначала отдельными операторами их вычислить, запомнить результаты в виде логических переменных и эти переменные уже помещать в условие.
  • == — не нужно. Присваивание не должно иметь никакого «возвращаемого» значения. Например, в x86 я могу присваивание x=y; реализовать как «push y» и «pop x». Где здесь «значение»?

     2023/01/04 15:18, Gudleifr          # 

Присваивание не должно иметь никакого «возвращаемого» значения. Например, в x86 я могу присваивание x=y; реализовать как «push y» и «pop x» Где здесь «значение»

В Си возвращаемое значение возвращается в аккумуляторе. Т.е. любое помещение чего-то в аккумулятор "возвращает значение".

     2023/01/04 16:28, kt          # 

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

     2023/01/04 16:32, Gudleifr          # 

А здесь могут получаться лишние и бессмысленные команды.

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

     2023/01/04 18:29, Автор сайта          # 

Тут можно вспомнить такую аналогию: машинная команда целочисленного деления имеет результатом не только частное, но и остаток от деления. Это «на сдачу», совершенно бесплатно. Хочешь — пользуйся, не хочешь — нет. Так и результат операции «присвоить»: если хочешь — получи его бесплатно. Например:
put (a = b);
Но за этим, конечно, скрываются некоторые подводные камни.
  • Во-первых, из-за этого нельзя отличить присвоение и проверку на равенство (это уже неоднократно обсуждалось).
  • Во-вторых, с точки зрения функционального программирования невостребованность результата какой-то функции — это повод сделать вывод о ненужности вызова этой функции. Что должно привести как минимум к невызову этой функции, а как максимум — к удалению этой функции, если она вызывается единожды, именно в этом месте. Но это, конечно, если функция чиста.

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

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

     2023/01/04 19:29, kt          # 

если хочешь — получи его бесплатно

как раз в случае реализации присваивания через push y + pop x не бесплатно, а специально для этого добавляемой командой, которая часто (а в наших программах всегда) не нужна.

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

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

     2023/01/04 20:01, Автор сайта          # 

Приведу цитату:

Раздельные операции [«&» и «&&», «|» и «||» и т.д.] нужны для избавления от скобок.

То есть у «&» один приоритет, а у «&&» — другой, побитовая «и» исполнится раньше, чем логическая. За счёт этого можно избавиться от лишних скобок.

     2023/01/04 21:30, kt          # 

Я бы все-таки предпочел лишние скобки (так как это наглядный парный знак), чем лишние &. И я не воспринимаю "битовые" и отдельно "логические" операции, поскольку "с детства" имею дело с языком, где есть объекты — битовые строки. А потому логические и битовые операции — это одни и те же, а булевы переменные просто строка длиною в один бит.

     2023/01/04 21:52, Автор сайта          # 

В Си есть ещё такая фича, что в логических (но не побитовых) выражениях нулевое значение — это «ложь», а всё остальное — истина. Например:
 a = 1; b = 2;
if (a && b)
равнозначно
 если «истина» и «истина»
что в итоге «истина». Если же
 if (a & b)
то побитое «и» операндов 1 и 2 дадут 0, то есть это будет «ложь». Это не совпадает с результатом a && b. Вот одна из главных причин, почему в Си-подобных языках операции «&» и «&&» — это отдельные операции.

     2023/01/04 22:28, Gudleifr          # 

if (a && b)... if (a & b)

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

     2023/01/05 00:32, Автор сайта          # 

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

     2023/01/05 00:54, Gudleifr          # 

недостойный технических дискуссий

Быдло-метод — это, может и непривычно звучит, но точно отображает способ программирования: сохраняя навязанные текущей системой ограничения и по-максимуму используя её библиотеки и интерфейсы. Например, так было создано большинство UNIX-утилит, которые делали ровно то, что надо, и добавлялись в ОС сразу, как начинали хоть как-то функционировать.

     2023/01/05 11:13, kt          # 

операции «&» и «&&» — это отдельные операции

С моей точки зрения — потенциальный источник недоразумений и ошибок.
Я всех заставил писать, что-то вроде:
dcl x bit(8);
if (x & 'c0'b4) ='00'b4 then...

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

     2023/01/05 11:14, Gudleifr          # 

P.S. Ругательное "быдло" прилепилось к этому методу из-за невозможности программиста в этих условиях найти свой баланс — https://gudleifr.forum2x2.ru/t15-topic#389 — выбор уже сделали до него.

     2023/01/05 11:28, kt          # 

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

Это выполнялось для архитектур типа PDP-11 и БЭСМ-6.
А, например, в x86 оператор x+=1; удобнее реализовывать одной командой как inc x. И никакого аккумулятора не используется. Впрочем, при разработке x86 (примерно 1977) имели ввиду не Си, а PL/1 ))

     2023/01/05 11:30, Gudleifr          # 

Я всех заставил писать

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

     2023/01/05 11:47, kt          # 

Тогда проще без if-oв


Зачем такие крайности? Условный оператор всеми легко воспринимается.
Приведенный же мною пример, во-первых, яснее выражает замысел: "я именно хочу проверить, что два старших бита сброшены" и прямо так и пишу. А, во-вторых, демонстрирует одинаковость "битовых" и "логических" операций, если в языке явно есть битовые строки. Есть только "битовые", а "логические" — частный случай "битовых"

     2023/01/05 12:21, Gudleifr          # 

Условный оператор всеми легко воспринимается.

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

Добавить свой отзыв

Написать автору можно на электронную почту
mail(аt)compiler.su

Авторизация

Регистрация

Выслать пароль

Карта сайта


Содержание

Каким должен быть язык программирования?

Анализ и критика

●  Устарел ли текст как форма представления программы

●  Русский язык и программирование

●  Многоязыковое программирование

Синтаксис языков программирования

Синтаксический сахар

●  Некоторые «вкусности» Алгол-68

●  «Двухмерный» синтаксис Python

●  Почему языки с синтаксисом Си популярнее языков с синтаксисом Паскаля?

●  Должна ли программа быть удобочитаемой?

●  Стиль языка программирования

●  Тексто-графическое представление программы

●●  Разделители

●●  Строки программы

●●  Слева направо или справа налево?

●  Комментарии

●●  Длинные комментарии

●●  Короткие комментарии

●●  Комментарии автоматической генерации документации

●●  Нерабочий код

●●  Помеченные комментарии

●  Нужны ли беззнаковые целые?

●  Шестнадцатиричные и двоичные константы

●  Условные операторы

●  Переключатель

●  Циклы

●●  Продолжение цикла и выход из него

●  Некошерный «goto»

●  Изменение приоритетов операций

●  Операции присвоения и проверки на равенство. Возможно ли одинаковое обозначение?

●  Так ли нужны операции «&&», «||» и «^^»?

●  Постфиксные инкремент и декремент

●  Почему в PHP для конкатенации строк используется «.»?

●  Указатели и ссылки в C++

●●  О неправомерном доступе к памяти через указатели

●  Обработка ошибок

●  Функциональное программирование

●●  Нечистые действия в чистых функциях

●●  О чистоте и нечистоте функций и языков

●●  Макросы — это чистые функции, исполняемые во время компиляции

●●  Хаскелл, детище британских учёных

●●  Измеряем замедление при вызове функций высших порядков

●●  C vs Haskell: сравнение скорости на простом примере

●●  Уникальность имён функций: за и против

●●  Каррирование: для чего и как

●●  О тестах, доказывающих отсутствие ошибок

●  Надёжные программы из ненадёжных компонентов

●●  О многократном резервировании функций

●  Использование памяти

●  Почему динамическое распределение памяти — это плохо

●  Как обеспечить возврат функциями объектов переменной длины?

●●  Типы переменного размера (dynamically sized types, DST) в языке Rust

●●  Массивы переменной длины в C/C++

●●  Размещение объектов в стеке, традиционный подход

●●  Размещение объектов переменной длины с использованием множества стеков

●●  Размещение объектов переменной длины с использованием двух стеков

●●  Реализация двухстековой модели размещения данных

●●  Двухстековая модель: тесты на скорость

●●  Изменение длины объекта в стеке во время исполнения

●●  Размещение объектов переменной длины с использованием одного стека

●  Можно ли забыть о «куче», если объекты переменной длины хранить в стеке

●  Безопасность и размещение объектов переменной длины в стеке

●  Массивы, структуры, типы, классы переменной длины

●  О хранении данных в стеке, вместо заключения

●  Реализация параметрического полиморфизма

Описание языка

Компилятор

Отечественные разработки

Cтатьи на компьютерные темы

Компьютерный юмор

Новости и прочее




Последние отзывы

2024/04/18 00:21 ••• Ильдар
Энтузиасты-разработчики компиляторов и их проекты

2024/04/15 00:00 ••• alextretyak
Признаки устаревшего языка

2024/04/11 00:08 ••• Автор сайта
Постфиксные инкремент и декремент

2024/04/09 23:50 ••• Автор сайта
Русский язык и программирование

2024/04/07 15:33 ••• MihalNik
Все языки эквивалентны. Но некоторые из них эквивалентнее других

2024/04/01 23:39 ••• Бурановский дедушка
Новости и прочее

2024/04/01 23:32 ••• Бурановский дедушка
Русской операционной системой должна стать ReactOS

2024/03/22 20:41 ••• void
Раскрутка компилятора

2024/03/20 19:54 ••• kt
О многократном резервировании функций

2024/03/20 13:13 ••• Неслучайный читатель
Надёжные программы из ненадёжных компонентов

2024/03/07 14:16 ••• Неслучайный читатель
«Двухмерный» синтаксис Python

2024/03/03 16:49 ••• Автор сайта
О неправомерном доступе к памяти через указатели

2024/02/28 18:59 ••• Вежливый Лис
Про лебедей, раков и щук