Подтвердить что ты не робот

Почему C и С++ не встроены в способы проверки переполнения целых чисел?

Почему C и С++ не предоставляют набор выполняемых операций реализации для выполнения каждой из основных операций с целыми числами с проверкой переполнения (например, a bool safeAdd(int *out, int a, int b)).

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

Таким образом, если компиляторы не способны выполнять намного лучшую работу, создавая более простые и быстрые операции, чем то, что можно кодировать на C и С++?

4b9b3361

Ответ 1

C и С++ следуют центральному принципу: "Вы не платите за то, что вам не нужно". Таким образом, арифметические операции по умолчанию не будут отклоняться от базовой инструкции базовой архитектуры для арифметических операций.

Что касается того, почему нет стандартной функции библиотеки для добавления двух целых чисел и обнаружения переполнения, я не могу сказать. Прежде всего, кажется, что язык определяет знаковое целочисленное переполнение как undefined поведение:

В языке программирования C сглаженное целочисленное переполнение вызывает поведение undefined,

Учитывая, что существует множество способов реализации знакового целого (одно дополнение, два дополнения и т.д.), и когда C был создан, все эти архитектуры были распространены, и понятно, почему это undefined. Было бы сложно реализовать "безопасную" чистую функцию C без большой информации о базовой платформе. Это можно было бы узнать на основе процессора за процессором.

Тем не менее это не делает невозможным. Мне определенно было бы интересно, если кто-то сможет найти предложения в органах стандартов C или С++ с более безопасными помощниками переполнения и сможет понять, почему они были отклонены.

Несмотря на это, на практике существует множество способов для обнаружения арифметических переполнений и библиотек.

Ответ 2

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

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

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

Ответ 3

Вопрос возникает регулярно.

Во-первых, помните, что C определяется как переносимым и эффективным. Таким образом, он был разработан только для операций, поддерживаемых большим количеством аппаратного обеспечения (возможно, до того, как x86 даже увидели свет в день).

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

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

Ответ 4

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

Когда вам действительно нужно знать, изменил ли результат диапазон int, а не знать, является ли результат внутри допустимого домена для определенного алгоритма или если индекс находится внутри границ массива? Именно вы даете переменные семантике, спецификация языка предоставляет только общие диапазоны типов, и если вы выбрали тип, диапазон которого не соответствует вашим потребностям, то это ваша ошибка.

Целочисленное переполнение - это UB, потому что вы редко очень заботитесь об этом. Если мой unsigned char переполняется во время операций, я, вероятно, выбрал неправильный тип для накопления 10 миллионов номеров. Но знание о переполнении во время выполнения не поможет мне, так как мой дизайн все равно сломан.

Ответ 5

Почему? Ну, потому что они не были в C, когда С++ начал с этого, и потому, что с тех пор никто не предлагал такие функции и не смог убедить компиляторов и членов комитета в том, что они достаточно полезны для предоставления.

Обратите внимание, что компиляторы do предоставляют такие виды внутренности, так что дело не в том, что они против них.

Заметьте также, что есть предложения стандартизировать такие вещи, как Арифметика с фиксированной точкой и Неограниченные целые типы.

Так что, вероятно, просто недостаточно интереса.

Ответ 6

Лучше может быть вопрос: почему происходит переполнение целых чисел undefined? На практике 99,9% всех процессоров используют два дополнения и бит переноса/переполнения. Таким образом, в реальном мире, на уровне ассемблера/кода операции, целые переполнения всегда хорошо определены. Фактически, многие ассемблеры или связанные с аппаратным обеспечением C в значительной степени зависят от четко определенных целых переполнений (в частности, драйверов для оборудования таймера).

Исходный язык C, до стандартизации, вероятно, не рассматривал такие вещи подробно. Но когда C получил стандартизацию ANSI и ISO, они должны были следовать определенным правилам стандартизации. Стандартам ИСО не допускается смещение к определенной технологии и тем самым дать определенные преимущества компании в конкуренции.

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

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

Разумным решением этой проблемы было бы не изобретать некоторые безопасные проверки диапазона, а скорее утверждать, что все знаковые целые числа на языке C должны иметь два дополнительных формата, конец истории. Тогда unsigned char всегда будет от 0 до 127 и переполняется до -128, и все будет хорошо определено. Но искусственная стандартная бюрократия препятствует тому, чтобы стандарт стал нормальным.

В стандарте C есть много таких проблем. Выравнивание/отступы, endianess и т.д.