2016-02-01 4 views
-1

Скажем, я хочу напечатать некоторые значения. Я предполагаю, что я должен получить Integer Overflow, если моя подписанная переменная превышает от TMin и TMax (в этом случае, используя 4 байта int, 0x7FFFFFFF как Tmax и 0x80000000 как Tmin), но в этом примере я не получаю то, что ожидаю (объяснено в комментарии):Не получать Integer Overflow

// Tmax = 0x7FFFFFFF == 2147483647 
// Tmin = 0x80000000 == -2147483648 
printf("1- overflow test: %d\n", 0x7FFFFFFF+1); // overflow - how compiler finds out it's a signed value, not an Unsigned one 
printf("2- overflow test: %d\n", 0x80000000-1); // in contrast, why I am not getting an integer overflow here 
printf("3- overflow test: %d\n", (int) 0x80000000-1); // overflow (Expected) 
printf("4- overflow test: %d\n",(int) (0x7FFFFFFF+1)); // overflow (Expected) 
+0

Первый - вы используете подписанное форматирование. Второй - литерал вычисляется во время выполнения, поэтому переполнение не происходит. В любом случае, подписанные переполнения не определены. – TNW

+0

@TNW выражение во времени компиляции рассчитывается как '0x7FFFFFFF + 1'. –

+0

@TNW, так почему существует отличное поведение для # 1 по сравнению с # 2 (так как синтаксис выглядит одинаково для меня) – Yar

ответ

1

ОП не всегда сталкивается с целым переполнением со знаком, что является неопределенным поведением.

Следующая математика без знака, так как 0x80000000, вероятно, является целым числом без знака. Шестнадцатеричные константы такого типа, который подходит им первого int, unsigned, long, unsigned long, ...

printf("2- overflow test: %d\n", 0x80000000-1); 

0x80000000-1 является беззнаковым типом как 0x80000000 первых припадков в беззнаковом типе, которые могут unsigned со значением 2147483648u. 2147483648u - 1 ->2147483647u.

0x7FFFFFFF+1 является знаковым типом, как 0x7FFFFFFF первых припадков в знаковом типе, вероятно int со значением INT_MAX.
int + int ->intиINT_MAX + 1 -> переполнение.


ОП сказал: «0x80000000 как Tmin», безусловно, является неправильным пониманием. В C, с 32-битным int/unsigned, 0x80000000 является шестнадцатеричной константой со значением 2147483648. Для ОП Тмин более вероятен -INT_MAX - 1.

+0

Как только вы вызываете UB, все ставки отключены, независимо от того, остальное в порядке. IOW: UB является вирулентным. – Olaf

+0

@ Замечания кода Olaf OP «почему я не получаю переполнение целых чисел здесь», безусловно, обнаружено из-за отсутствия предупреждения о времени компиляции. Причина в этом ответе обсуждается. Конечно, UB - это проблема времени выполнения. – chux

+0

Хорошо, ты понял. Мой комментарий был в основном тем, что после первого переполнения все ставки отключены для следующего кода. – Olaf

2

Прежде всего, позвольте мне сказать вам, (подпись) целочисленное переполнение вызывает undefined behavior.

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

Просто для уточнения, даже

printf("2- overflow test: %d\n", 0x80000000-1); 

является UB. Хотя 0x80000000-1 - unsigned, а не переполнение само по себе, использование %d приведет к несоответствию типа, которое технически приведет к UB.

Что касается неопределенного поведения, от C11, приложение §J.2,

Преобразование в или из целого типа производит значение вне диапазона, который может быть представлен .

+0

Как насчет подписанного 'long'' подписанного 'char'? и т.д.? (Извините за то, что я никому не нужен. Просто подумайте об общем ;-) – Olaf

+0

@Olaf меняет это на «подписанные целочисленные типы», делает его лучше? –

+0

@Olaf Я имею в виду раздел 6.2.2/17. Это будет нормально? :) –

1

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

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

Возможно, ваша система решила, что ее целые числа больше. Только нижний предел целочисленных размеров (2 байта) задан в c (по крайней мере 4 типично для стандартных компьютеров). Ваша система может иметь 8 байтовых целых чисел или даже больше.

+0

, так что если переполнение int происходит довольно случайным образом, как мы можем определить, скажете ли случайный ввод получить переполнение или нет? – Yar

+0

@HoomanYar Обеспечивая, чтобы ваше значение не превышало допустимого в вашем целого числа. Переполнение происходит только тогда, когда вы выходите выше этого. Поэтому, если ваш int 32 бит (что, скорее всего, это так), просто не делайте над 2^32 -1 по значению или не более 2^32/2 - 1 для целых чисел со знаком, а не ниже - 2^32 для целых целых чисел – Magisch

+0

* «Только нижний предел целочисленных размеров (4 байт) задан в c." * - 2 байта, конечно? –

1

C является несовместимым с численными исключениями.

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

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

unsigned int i = UINT_MAX; 

, а затем добавить к нему 1, это гарантировано, чтобы обернуть вокруг 0.

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

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