Как стать автором
Обновить

Объявляю ошибку вида if (x = 42) вымирающей и заношу её в Красную книгу C и C++ багов

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров39K
Всего голосов 61: ↑60 и ↓1+80
Комментарии109

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

Clang выдает предупреждение на такой if.

gcc тоже. В целом, это тривиальная проверка, которую можно делать тупо на уровне AST вообще без какого-то сложного анализа кода.

Да даже Python уже проверяет:

x = 2
if False:
     if x = 2:
        print("= 2")
print("OK")

При том не в рантайме, где исполнение до того присваивания заведомо не дойдёт, а заранее ошибку выдаёт:

line 3
    if x = 2:
       ^^^^^
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?

Для python это невалидный синтаксис (о чем и говорит ошибка). Для C/Java/C++ это валидный синтаксис, но не рекомендуемый (по причине потенциальной опасности)

У меня, может, ложная память, но, кажется, в старом Python у меня до рантайма подобное доживало. Проверять, конечно, не буду.

До версии 3.8 в питоне не было оператора :=

Да, но нет :). Если хочется сделать хорошо, нужно учитывать разные паттерны и тонкости. В PVS-Studio в диагностике V559 есть с десяток исключений, когда ругаться не надо, что-бы не раздражать программистов. Например, всё хорошо, если написано:

while(*to++ = *from++)

а если while (*from++ = *to++) ? :)

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

Причина ошибки в коде на картинке заключается в том, что булевские переменные не требуется сравнивать. Они же булевские! У них даже название сделано таким чтобы можно было написать if (IsCrasyMurderingRobot)

Но вообще когда код убийства явно присутствует в программе, вряд ли можно говорить "Мы их на это не программировали"

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

Они ещё и камел кейс юзают с паскаль кейсом одновременно ?

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

Я тоже использую :)

Последствия работы с java и прочими си-подобными языками.

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

Раньше (до рефакторинга) там была функция, которая возвращает int, который автоматически (хе-хе) конвертится в бул и все работало. Но тестов (конечно же) не было и небольшой рефакторинг привел к СДЕЭКу.

Ну на самом деле такие ошибки обычно не при сравнении с true/false, а с -1 и т.п. True/false это просто особенно ярко и красиво :)

сейчас опечатки делают также часто, как и 10 лет назад

И так же часто забывают про пробелы ;)

Современные компиляторы умеют распознавать опечатку в сравнении и показывать предупреждение в таких случаях. В дополнение к этому предупреждения могут обрабатываться как ошибки, что вызовет ошибку сборки в случае опечатки.
В Compiler Explorer видно, что и clang, и gcc, и msvc выдают ошибку с правильными флагами компиляции:
https://godbolt.org/z/G73b6sbTM

Так про это в статье написано

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

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

А восьми лет недостаточно, чтобы так утверждать?

О каких 8 годах идет речь? Вы о чем сейчас?

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

Судя по вашему тону, сраться в комменты пришли вы, а не я

В статье упоминается что последняя подобная ошибка автором была найдена в 2016 году (8 лет назад). Полагаю речь про это.

Из этого же не следует, что "теперь не осталось компиляторов, которые промолчат, встретив присваивание в условии"? Проекты под проверку PVS Studio же не случайно выбираются, а по популярности, объему кода и т.д. Выборка скорее всего смещенная. Тот же Хромиум разрабатывают в Гугле и качество кода там скорее всего выше, чем в целом в индустрии.

Вот мне делать больше нечего :) Наверняка найдутся какие-то компиляторы без такой диагностики. Например для embedded или просто старые, но ещё где-то используемые. Но речь про общий тренд. Компиляторы и анализаторы вытравили такие баги из кода в целом :)

В мейнстримных компиляторах диагностика ушла вперед, да. Но тот же gcc без флагов -Wall -Werror не покажет никакого предупреждения про некорректное присваивание. В топовых open source проектах это скорее всего включено, поэтому такие ошибки оттуда ушли.

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

А можно было сделать присваивание с дополнительным символом, например x := 42

Pascal, Python?

Python, начиная с версии 3.8

Или "равно" назвать устаревшим и продвигать x{42}, чтобы новые компиляторы стали ещё придирчивее к одиночному "равно".

А как тогда мутировать переменные?

Покажите пример.

int x{42};
for (int i = 0; i < N; i++) {
  x = f(x); // что сюда написать? int x{f(x)}; уже не получится.
}

Фигурные скобки используются только для инициализации?

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

  auto rng = std::ranges::iota_view{0, N};
  int x{std::accumulate(rng.begin(), rng.end(), 42, [](int _, int b){ return f(b); })};

И компилируется в ровно такой прямой цикл: https://godbolt.org/z/W6zzWcvbn

Историческое усилие сделать объем файлов меньше

Есть ещё путь 1С, где в проверках условий или внутри присваивания знак "=" уже не является присваиванием.

Например,

Если (Перем1 = 42) Тогда

Или

Перем1 = Усл1 = 42;

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

Она теперь будет жить в веках.

let number = Some(5)
if let Some(i) = number {
    println!("Это пять: {:?}!", i);
}

Я вообще не понимаю, какой в ней смысл?

Если ты вспомнил о ней и переписываешь if раком - ну тогда ты уже и == написать сможешь. Если не вспомнил - то и так и так баг будет.

Единственный случай когда она помогает, это когда программист йодирует свой мозг и потом читает код и его передергивает от каждого if в человеческой нотации. Но йодировать свой мозг - слишком дорогая цена.

Я вообще не понимаю, какой в ней смысл?

Если случайно написать "=" вместо "==", то выражение if (x = null) скомпилируется и будет всегда true, а если писать наоборот, то выражение if (null = x) выдаст ошибку компиляции.

Ну так не пишите неправильно, пишите правильно. Что сложного то? :-)

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

Мне это напоминает математика, который коров посчитал. Посчитал ноги, разделил на четыре.

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

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

Я такое видел в коде на шарпах, причем люди, которые это писали просто это где-то увидели и повторяли. Зачем это надо никто их них не знал, просто тут так принято. Чего-то совсем плохого тут нет, но карго культ налицо)

Вот отсутствие критического мышления и есть то самое "совсем плохое".

Бывает и хуже)

Я до сих пор такое вижу на шарпах у себя в конторе. Есть у нас один тип (по совместительству тимлид), который настолько привык к использованию нотации Йоды на плюсах, что не смог от неё отказаться при переходе на шарпы. Настолько не смог, что разворачивает пул-реквесты на шарпах, при обзоре которых обнаруживает "нормальное" (переменная слева) использование оператора сравнения. Но впрочем здесь проблема уже более глкбокая - я её называю "ревностное отношение к корпоративному коду". К сожалению, в штате конторы нет психиаторов.

ну в жаве например она неплохо помогает избежать NPE при сравнении строк )))

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

Так нет же никакого исключения для обёрток примитивов.

При сравнении с литералом точно есть.

Integer i = 5;
String s = "habr";
if (i == 5) .... //true
if (s == "habr") ..... //false

Могли бы сделать исключение хотя бы для случая, когда идет сравнение со строковым литералом в коде. Понятное дело, что технически это не литерал, а объект. Но тут очевидно, что программист точно не имел в виду сравнить указатели, потому что в выражении типа if (s == "habr") указатель на "habr" сразу же выкидывается. И более того, это выражение по идее будет всегда false, потому что указатель на свежесозданный объект явно не будет равен какому-то существовавшему ранее. Поэтому можно было бы смело обрабатывать такую запись как "habr".equals(s)

видел такое в китайских исходниках, тогда подумалось, что это какая-то хитрая оптимизация :D

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

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

Например, vim в разных вариациях

Не надо считать странными всех, с чьими проблемами вы лично не сталкивались. Я вдиел нескольк действительно большимих проблем в использовании IDE

1) Кастомные скрипты сборки, подгрузки ресурсов, зависимостей, тестирования и тд и тп. Когда perl грузит модули, python собирает ресурсы, а bash перекладывает инклюды туда, где их увидит компилятор. Большинство IDE превращаются в тыкву в такой ситуации, не могут найти исходников, не видят реальных флагов компиляции и начинают подчёркивать всё, деградируя до тупого и очень визуально шумного текстового редактора. Подружить старый проект с такими скриптами с IDE - трудоёмкая задача с сомнительной пользой.

2) Удалённая разработка. Vim на сервере работает по ssh, можно вести разработку на монстр-сервере с терабайтом памяти и 64 ядрами, что очень сильно ускоряет компиляцию, упрощает разворачивание общей для разработчиков среды и тд. Кроме того на продуктовом сервере можно иметь привычное окружение разработчика, чтобы дебажить наживую. Да, VS Code сейчас позволяет делать что-то похожее, но это появилось недавно на фоне C++.

3) Топорность и скромный функционал по работе с текстом. Мультикурсоры, редактирование всех вхождений, да банальный сдвиг блока кода не на 1 таб, а на 1 пробел - тривиальные задачи для вимеров и сложные в большинстве IDE.

4) Тяжеловесность IDE и тормоза даже на современных компах. Любимый текстовый редактор открывается за миллисекунды и готов к работе. IDE лагают на простых операциях, как текстовый поиск - сравните с тем же grep на большом проекте.

5) Погуржённость в инструментарий. Если вы пишите в редактори и с консольки собираете проект, то скорее всего вы понимаете, как он собирается или можете открыть скрипт сборки и прочитать. Что и когда делает IDE - чёрный ящик, залезть в который гораздо сложнее.

Я пока со всем этим не столкнулся, тоже не понимал, что это они в каменном веке сидят. А когда потратил дни на то, чтобы всё же внедрить умную IDE, понял, что часто оно того не стоит. Я почти познал дзен с VS Code, но сейчас работаю на проекте, где только большая VS и солюшн только под него - это ад: тормоза при функционале меньшем, чем в VS Code.

3) Топорность и скромный функционал по работе с текстом. Мультикурсоры, редактирование всех вхождений, да банальный сдвиг блока кода не на 1 таб, а на 1 пробел - тривиальные задачи для вимеров и сложные в большинстве IDE.

Это еще sublime с notepad++ умели, не говоря про VS Code и IDE от JetBrains.

5) Погуржённость в инструментарий. Если вы пишите в редактори и с консольки собираете проект, то скорее всего вы понимаете, как он собирается или можете открыть скрипт сборки и прочитать. Что и когда делает IDE - чёрный ящик, залезть в который гораздо сложнее.

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

Это еще sublime с notepad++ умели

sublime и notepad++ это и есть текстовые редакторы, это не IDE.

IDE сама ничего собирать не умеет

В случае MS VS это ещё какой сборщик и компилятор. С настройками не в конфиг файлах и скриптах сборки, а в интерфейсе. Именно IDE позволяют полностью оторваться от компилятора и понажимав кнопочки мышкой создать и собрать проект, не имея представления о том, как это работает. Это уже скорее проблема обучения программированию, а не работы, но всё равно вызывает дискомфорт. За это я люблю VS Code, она вроде как и IDE, но фактически редактор, который запускает понятные скрипты и не делает ничего неявно.

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

А почему у полной VS функционала меньше, чем в VS Code?

  1. О, у меня были такие проекты да. Такой адовый мусор, собираемый баш скриптами :D Это на помойку надо выбрасывать, а не агитировать против IDE.

  2. Вы описали CI\CD сейчас. Опять же не понятно, причем тут вим.

  3. Ни разу за 10 лет карьеры не сдвигал код на один пробел. Но скорее всего это элементарно делается выделением нужного куска кода, и заменой там N общих пробелов в блоке на N+1.

  4. Я игрался с кодом гигантского Unreal Engine, имея на тот момент i7-9700K. Открывался за 10 секунд со всей подсветкой, индексированием, автодополнением и прочими радостями жизни. 1 раз в рабочий день. Такой себе аргумент. Греп я практически не использую в работе, т.к. он не контекстный. В больших проектах слишком много шума грепать что-либо. А вот контекстный поиск используется постоянно.

  5. Какая разница Cmake собирать из консольки, или нажать кнопку Build в той же вижуал студии? Если для сборки проекта надо сделать больше, чем кнопка Build - это плохо собираемый проект.

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

Это на помойку надо выбрасывать

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

Вы описали CI\CD сейчас. Опять же не понятно, причем тут вим.

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

Ни разу за 10 лет карьеры не сдвигал код на один пробел

Это не значит, что это никому не нужно. Стандарты форматирования разные бывают, далеко не всё можно объяснить clang-format пока что.

Греп я практически не использую в работе

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

Если для сборки проекта надо сделать больше, чем кнопка Build - это плохо собираемый проект.

Последний пункт зацикливается на первый, что делать-то с такими проектами? Они важны и нужны. Переписывать всё на CMake? Занимался я таким и не мало - дело долгое и не благодарное, потому что продуктивность разработчиков от этого не меняется. Разве что скорость вхождение новичка повышается.

у нас все собирается за 1 кнопку, всем контора покупает вижуал студию

Это личный опыт. У меня он противоположный, я прешёл в большую контору с вижуал студией и скучаю по временам перловых скриптов сборки. Их я мог прочитать и переделать инструментарий так, как мне удобно, выбрать IDE или редактор, который я могу настроить удобно, а сейчас я этого лишён.

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

С очень большой вероятностью в нестандатной сборке буста не будет смысла, если сам проект собирается нормально. У нас используется "vcpkg install boost-нужные-либы" например, без каких-либо ухищрений.

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

Честно говоря - плохо могу представить, что за проект, который локально не скомпилировать. Типа.. где-то же он компилируется, почему он локально то не может скомпилироваться? Опять традиционные проблемы адовых костылей и месива из батников\башскриптов? Если говорить про супер-кроссплатформу мак\винда\линукс - ну пришлось бы макмини у конторы выпросить какой-нить допником. Не вижу проблемы.

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

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

Последний пункт зацикливается на первый, что делать-то с такими проектами? Они важны и нужны. Переписывать всё на CMake? 

Да, мы выделяли время на переезд с БАТНИКОВ на Cmake (не скажу, что я люблю Cmake, но что поделать), с "вот в эту папочку подложите вот это, и енввары проставьте" на vcpkg. И это окупилось сторицей. У нас в Readme.md инструкции сборки - Поставьте последнюю Вижуал Студию 2022 & Нажмите Build.

В CI этап сборки состоит из 1 строки - cmake --четотам

Если в инструкции по сборке больше 1 шага - что-то очень сильно не так с проектом.

скучаю по временам перловых скриптов сборки

Ну это, на самом деле, всё обьясняет. Перловые скрипты сборки должны быть каленым железом выжжены с каждого hdd\ssd. Сейчас 2024 год, а не 1994.

Как и обьясняет тезис о несобираемом проекте локально :D

С очень большой вероятностью в нестандатной сборке буста не будет смысла

Я не про использование буста, я про разработку самого буста. И он такой не один, возьмите достаточно старый живой проект и там не будет CMake. Первое, что приходит в голову кроме буста - GCC. Кто-то смог и перешёл, а кто-то ещё использует autotools или ручной make, например.

Типа.. где-то же он компилируется, почему он локально то не может скомпилироваться?

Оно компилируется и работает только под линуксом. За кроссплатформенность никто платить не готов, да и даже она не решает задачу дебага на конкретной платформе. Разработчики тоже не готовы сидеть под линуксом, и даже в этом случае десктопный будет отличаться от серверного и будет сборка в контейнере без иксов и красивой IDE. Ваш выбор в этой ситуации - vim, который с плагинами хотя бы видит правильные инклюды, или IDE на хосте, которая не будет видеть вообще ничего. Ну и прямо сейчас - VS Code с Remote плагином, но это фактически запуск IDE на удалённом хосте.

Ну это, на самом деле, всё обьясняет.

Вы меня совершенно не поняли. Я не предлагаю отказаться от CMake и вернуться к баш скриптам. Я сам стараюсь им пользоваться и делать так, чтобы cmake --build собирал всё, на всех платформах и не требовал ничего. Мой тезис в том, что это может оказаться настолько дорого, что не будет иметь никакого практического смысла.

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

Тут проблема больше не в IDE, а в том на чем эти IDE сейчас пишут. Наитивный исполняемый код для них увы не в моде.

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

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

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

Кухонный нож - тоже смертельно опасная штука.

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

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

Глупость полнейшая вообще проверять логические переменные на true false. С логическими максимум использую инверсию.

if(isCorrect) {....}

if(!isCorrect) {...}

Странно, кто-то не согласен с этим очевидным утверждением. Скажу больше: писать if (x == true) недопустимо! Потому что x может оказаться не bool, а у неё истинное значение может быть любым кроме 0.

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

Это ещё что! Программисты вначале создали проблему "а давайте временные переменные (в т.ч. массивы) пихать туда же, куда и адреса возврата" (т.е. в стек), а потом уже которое десятилетие плачутся, что эту фичебагу имеют в хвост, гриву и прочие места всевозможные хакеры.

какая альтернатива то?

Элементарная — два отдельных стека: один — для данных, другой — для адресов возврата. Проблема с переполнением массива, затирающим адреса возврата, ликвидируется в корне.

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

К сожалению у большинства процессоров память одна и два твоих стека всё равно будут в одной памяти,

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

Так вот и я про то же: никто не мешает компилятору иметь ДВА стека. Но так почему-то не делают.

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

Так вот и я про то же: никто не мешает компилятору иметь ДВА стека

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

Я не буду сейчас с Вами спорить, потому как последние N лет не смотрел, что там наворотили в компиляторах на эту тему, но а) речь не о том, что "компилятор знает по какому адресу находятся переменные, а по какому - адреса возврата" — речь о том, что это разделение нарушается при работе программы, когда компилятора уже и след простыл; б) для решения именно этой проблемы и был придуман NX-бит, в) два стека эту проблему вполне себе решат (особенно если они расположены в совершено разных местах памяти); если Вы себе визуально представить не можете, почему — то могу Вам только пособолезновать, не быть Вам системщиком.

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

Программисты вначале создали машину "а давайте она будет за нас задачи решать",

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

(Надеюсь, не надо Вам объяснять,

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

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

Ну это же сознательное упрощение ради шутки. Конечно не всё так просто на деле.

Проблема в том, что будущее предсказывать (все последствия, и насколько каждое из них будет высомо) не умеем. Карты таро не преподают на информатике. :-). Поэтому ВСЕ что делается в IT - делается как-то сиюминутно, на соплях и синей изоленте. Все - черновики, которые в продакшне.

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

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

= сравнение
== строгое сравнение
-> и <- присвоение (направление стрелки указывает источник и приемник значения, i <- 1 или 1 -> i)
. навигация по любой иерархии. Всегда точка, а не точка или стрелка в зависимости от контекста.

Если в операторе стрелки ошибиться с пробелами и создать либо двусмысленность (i<-1 это "присвоить единицу в i", или "i меньше минус единицы"?), либо бессмысленное сравнение (i < -1 и всё) - выкинуть ошибку компиляции.

Да, необычный синтаксис, но не необычнее той же иерархии кода в питоне.

А что такое строгое и нестрогое сравнение?

что такое строгое и нестрогое сравнение?

— А почём он помидоры продаёт?
— Ну, рублей пять-шесть!

Проверка совпадения типа данных, которая традиционно обозначается ===

Я знаю только С++, так что можно пример на нём? А то всё равно непонятно что это и где надо.

Не знаю, есть ли такое в сишке, врать не буду. Из известных мне языков есть, например, в php и js. (1 == true) - это true, а вот (1 === true) - это false. Значение совпадает, но не совпадает тип.

Т.е. это проверка на этапе компиляции?

И PHP, и JS — не компиляторы, а интерпретаторы.

Вообще достаточно чёткий признак — посмотреть, есть ли в языке оператор (или метод) eval.

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

Есть машинный код — последовательность битиков, согласно которым процессор что-то делает. При этом не "думая", почему и зачем. Как я всегда говорю, "компьютер — это исполнительный идиот, который просто умеет очень быстро складывать".

Есть программный код — последовательность буковок, которую очень хорошо понимают человеки. (Некоторые человеки умеют понимать машинный код напрямую — например, я неплохо понимаю машинные коды PDP-11, — но их мало и это вымирающеее умение, которое сейчас как-то не особо и не нужно.)

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

Соответственно:

  • Для программы на интерпретируемом языке (JS, PHP...) программа-интерпретатор должна постоянно присутствовать в памяти, чтобы "переводить с человеческого на машинный". За счёт времени, которое тратится на такой перевод, интерпретируемые языки работают медленнее. Поскольку интерпретатор всё равно находится в памяти и ему всё равно, что интерпретировать — строку, взятую из файла, или произвольную строку — в таких языках могут иметься методы eval(какая-то_строка)"переведи строку и тут же сделай, что в ней приказано".

  • Для программы на компилируемом языке (C) компилятор нужен только один раз — при, собственно, компиляции, после чего получаем файл с машинным кодом, который уже будет непосредственно исполнен процессором безо всякого "перевода". Поскольку процессору переводить не надо, скомпилированные программы работают быстро, однако, во-первых, поскольку многое было выброшено при компиляции, могут быть упущены какие-то вспомогательные детали, а во-вторых, eval(строка) быть не может, ибо некому переводить — переводчика уже давно расстреляли уволили.

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

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

компиляторы PHP

Не видел ни одного настоящего компилятора PHP. Часть из того, что так называют — это продвинутые компакторы/обфускаторы, а часть — вдобавок к этому сбоку прилепляет бинарник с собственно интерпретатором PHP, так что внешне это выглядит как "единственный исполняемый файл", да.

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

Ну так если он переводил не в машинные коды, а "с одного языка на другой" — то это не компилятор (компилятор тут — условный gcc), а препроцессор.

Согласен, но разработчики назвали его compiler. Суть в том, что в конечном итоге программа на PHP превращается в честный нативный бинарь, так что процесс компиляции PHP возможен. Пусть и через промежуточный язык.

но разработчики назвали его compiler

Ну, Васисуалия Лоханкина родители тоже полудурком называли... ;)

Пусть и через промежуточный

Для такого финта ушами есть какое-то специальное название. Хочется сказать "кросс-компилятор", но нет, что-то другое, не припомню сейчас.

Тогда уж не препроцессор а транспайлер.

ох уж эти "проблемы" тех кто переходит с BASIC на C++...

В Фортране для сравнения (в том числе массивов, логических и символьных типов) используются операторы .eq. (==), .le. (=<), .ge. (>=), а для присваивания знак равенства "=".

И хотя это длиннее, чем ==, но не длиннее, чем (...==...), и гораздо понятнее, и ошибиться едва ли возможно - в глазах не так рябит.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий