Есть, но крайне сложно оказаться в такой ситуации, это или прыжки между 16/32/64 битными архитектурами, где совместимость ложится на плечи компилятора, где он чтото заворачивает хардварно, а чтото софтварно или же abi, где нагородили кучу стандартов, где не всё раскладывается по регистрам - вот тут оч хорошо расписаны разные случаи
Вот ты пришёл сюда и об этом спросил, значит ты понимаешь что делаешь потенциально небезопасную и непереносимую херню. Так а почему бы тебе её просто не делать?
тебе оно зачем? вообще-то это равно -1. то есть невозможный индекс в строке. но и это не стоит брать во внимание, и воспринимать просто как некую константу.
А если теперь сделать c++, то как раз-таки возникнет переполнение. Поэтому вычисления вблизи границы допустимых значений типа должны выполняться с проверками на переполнение. И да, char можно без потерь привести к int, но не наоборот. Хотя, это может быть машинозависимо.
В теории (судя по цппреференс), должна быть какая-то зависимость от one’s complement vs two’s complement, если в конверсии участвуют отрицательные числа. Например:
If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo 2n
where n is the number of bits used to represent the destination type.
That is, depending on whether the destination type is wider or narrower, signed integers are sign-extended[1] or truncated and unsigned integers are zero-extended or truncated respectively.
Тут же сноска
This only applies if the arithmetic is two's complement which is only required for the exact-width integer types. Note, however, that at the moment all platforms with a C++ compiler use two's complement arithmetic.
В общем что-то может где-то быть, но это какая-то пипец маргинальщина, под которую даже компилятора нет
Вот и я сейчас склоняюсь что не будет никакого UB.
Вот например пусть есть тип T1 он 1 байт, и тип T2 он пусть два байта
и так:
T2 = [0xFF][0xFF]
Далее если мы максимально возможное значение T2 сохраним в переменную типа T1 то вне зависимости от порядка байтов архитектуры у нас получится ровно максимально возможное значение типа T1 а другая часть (левая или правая, нам это не важно) отбросится.
$firkax поясни за диз. Вопрос с отрицательными числами сильно интереснее изначального (ответ на который очевиден), получается, что, типичный код:
int main() {
unsigned long long ul = -1;
assert(ul + 1 == 0);
}
не является переносимым. Что в общем-то логично для разного представления отрицательных чисел. Но компилятор могу там вставлять необходимые прибавки при конверсии. К счастью one’s complement вряд ли кто-то в глаза видел
Этот код переносимый. -1, скастованное в любой unsigned, приводится к максимальному значению того unsigned-а. Сначала signe -1 приводится к нужной разрябности (очевидно, это можно сделать без проблем т.к. -1 представимо в любом signed типе), а затем конвертируется в unsigned по правилам unsigned. Внутреннее представление чисел тут значения не имеет. Для современных процов описанные правила нативные, для других - будет получаться какой-то сложный код чтоб эмулировать то же самое.
Я не сам придумал, а посмотрел здесь, пункт Integral conversions.
а затем конвертируется в unsigned по правилам unsigned. Внутреннее представление чисел тут значения не имеет
Получается, что имеет, там черным по белому написано. Наверное, из-за неактуальности one’s complement просто никто не заморачивался. А зачем, если нет ни одного компилятора, умеющего генерить код под такое железо
Я не знаю, что означает эта сноска, смотри пункт выше (он без сносок)
If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo 2^n
where n is the number of bits used to represent the destination type.
тут по-моему всё однозначно расписано - исходное и новое числа должны быть равны по модулю 2^n.
На цппреференс прямые цитаты из стандарта. Нет там дыма без огня. Возможно всё кроме two’s complement вывели за скобки и не хотят парить себе мозг без надобности
И что? Процитированное мной там имеется безо всяких сносок и оговорок, и оно вполне однозначно описывает как это должно работать. А к чему относится сноска я не знаю, видимо у неё есть какой-то другой смысл.
Ты глупый? Там прямым текстом в первом абзаце написано как должен конвертироваться тип, и никаких сносок оттуда нет. Во втором абзаце, откуда сноска, какие-то дополнительные рассуждения, которые на результат не влияют.
Следи за словами, я тебя и проклясть могу. Ты, похоже, даже не очень понял суть своего любимого 1 пункта, там говорится, что беззнаковый приёмник равен остатку от деления 2^n. Понятно, что это касается случаев, когда источник больше приёмника. Сюда никак не могут входить случаи, когда источник меньше и надо делать sign-extension. Подпункт со сноской как раз конкретизирует это и объясняет что приосходит когди источник меньше и больше приёмника.
Понятно, что это касается случаев, когда источник больше приёмника.
Вот же ты упёртый. Нет там никаких оговорок! Это относится ко всем случаям. И не «остатку от деления», а «наименьшему представимому числу, равному по модулю».
надо делать sign-extension
sign-extension - это технические подробности того, как будет достигаться описанное в первом абзаце, вот видимо они и зависят от представления. А само правило указано в первом абзаце и оно не меняется.
modulo 2^n это не операция, а условие к уравнению.
То что твоя логика хромает я давно заметил. Так что прекращай фантазировать, возьми англо-русский переводчик чтоб не позориться незнанием языка и читай всё дословно как есть.
это оно определено для size_t — а эта константа неизвестно заранее как превратится в unsigned — с трункацией или без такового. Это уже имплементейшн дефайнед какие размеры данных типов на конкретной архитектуре.