Здравствуйте, vdimas, Вы писали:
V>По моему опыту, в плюсах беззнаковые используются часто, почти всегда чаще знаковых.
И вы, конечно же, сможете это подтвердить, дав ссылку на более-менее любой публичный C++ — проект.
V>Знаковые целые нужны редко, в основном для оперирования сущностями, близкому по смыслу к "разница", "текущий остаток/баланс", или для традиционного возврата кодов или признаков ошибок.
Угу.
Вся индустрия идёт не в ногу, только vdimas идёт в ногу.
V>У меня обсуждаемая проблема вечно вылазит в дотнете, бо системное АПИ расписано на знаковых, даже где это выглядит абсурдом.
Обсуждаемая проблема в дотнете вылезти не может, т.к. в нём знаковое переполнение не является UB.
V>Причина известна — не во всех языках есть беззнаковый тип, поэтому платформа затачивалась на слабое звено. ))
Опять смелая догадка.
V>Переполнения принято производить с беззнаковыми, а со знаковыми принято оперировать так, чтобы переполнения не возникало.
Не, просто 99% С++ программистов вообще не в курсе, что знаковое переполнение — это UB.
Большинство пребывают примерно в таком же заблуждении, как и вы — что это Implementation-defined.
V>Что код примера не обязательно выполняется в реальном железе, а порой только на этапе компиляции.
Я правильно понимаю вашу мысль, что причина ошибки тут — в том, что код примера выполнился на этапе компиляции, при этом там было какое-то такое железо, в котором (MAX_INT+1) оказался больше MAX_INT?
И этот неверный результат попал в конечную программу, которая должна исполняться на каком-то другом железе, где это не так?
Или я вас неверно понял?
V>Хороший пример, кстате.
V>Что в дотнете, что в плюсах такими вещами упражняюсь путём приведения к более широкому типу, поэтому int64 пролетает.
Ну, так какой ответ-то на этот пример?
V>Наверно, наоборот, compile-time вычисления произошли из предположения, что никакого UB не возникает, и тогда результат всегда false.
Давайте распишем это утверждение. "compile-time вычисления произошли из предположения, что никакого UB не возникает" — то есть что будет какое-то implementation-defined behavior.
И какое же поведение имел в виду компилятор?
V>Кстате, мне Решарпер в C# иногда подсвечивает "тут у вас всегда true" (или всегда false), т.е. намекает на мёртвые ветки кода, хотя не факт.
V>Спасает то, что компилятор C# и JIT пока мест не делают суровых оптимизаций.
Дело не в суровости оптимизаций. Применимые в данном примере оптимизации они таки делают.
V>(можно сказать, что компилятор C# не делает никаких оптимизаций от слова вообще, кроме совсем скромных манипуляций локальными переменными)
V>Когда в дотнете, наконец, случится обещанная тобой еще 20 лет назад суровая оптимизация — напорешься на аналогичные эффекты. ))
На аналогичные — нет. Ваши утверждения основаны на неверном понимании как С++, так и дотнета.
Давайте посмотрим, что делает дотнет в описанном примере:
https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABAJgEYBYAKGIGYACY8pJ0hgYQYG8aH+mjZq2AQIAGwYBJXAFlsCABQYAFgEtcDNQDsMDBAEoGAXgB8DRQgDU5IwB59Abj4D6TFlt0NZio72oCgUwA7J4YAHTyCABq2OIArjDhMlG+DAD8DOShIAwopM4BAgC+LvxuwmEMAHKKOnqGPGVBxKEIyXIKaZnZDLn5hYGl1MVAA===
Внимательно смотрим в код метода M и видим, что
а) оптимизатор заинлайнил код IsMax, как и следовало ожидать
б) оптимизатор выполнил compile-time вычисления, как и следовало ожидать
в) оптимизатор при этом вернул корректный результат. Опять-таки, как и следовало ожидать. И не потому, что он "не догадался" что-то там соптимизировать в неверную сторону, а потому, что в дотнете арифметика устроена не так, как в С++, в частности по отношению к знаковому переполнению.