Intereting Posts
Возможно ли «заставить» UTF-8 в программе на C? Как разумно интерпретировать это предупреждение компилятора? Какой тип данных «длинный»? Пожалуйста, объясните этот результат, пожалуйста. printf (“% c”, ‘abcd’) Включение файла заголовка из другого каталога Получите путь приложения без имени приложения в конце приложения. Есть ли способ отображать скрытые символы видимости с GNU binutils? Выполнение операции переключения в java Быстрая корреляция в R с использованием C и распараллеливание Почему компилятор жалуется на это объявление макроса Предупреждение: индекс массива имеет тип char Каков исторический контекст для long и int, который часто бывает одного размера? В чем разница между определениями char * str = {“foo”, …} и char str = {“foo”, …}? Как систематически следовать рекурсии? Как я могу прочитать переменное количество целочисленного ввода в C?

странный результат сравнения целочисленного неравенства C

#include  #include  int main() { long ival = 0; printf("ival: %li, min: %i, max: %i, too big: %i, too small: %i\n", ival, INT_MIN, INT_MAX, ival > INT_MAX, ival < INT_MIN); } 

Это дает результат:

 ival: 0, min: -2147483648, max: 2147483647, too big: 0, too small: 1 

Как это возможно?

(На самом деле я попал в эту проблему / ошибку в CPython 2.7.3 в getargs.c : getargs.c . Если вы посмотрите код, в case 'i' , есть проверка ival < INT_MIN которая всегда была верна для меня. также источник тестового случая с дополнительными ссылками .)


Ну, я тестировал несколько разных компиляторов. GCC / Clang, скомпилированные для x86, возвращают ожидаемый (слишком маленький: 0). Неожиданный вывод происходит из Clang в инструментальной цепочке Xcode при компиляции для armv7.


Если вы хотите воспроизвести:

Это точная команда компиляции: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk test-int.c

Это Xcode 4.3.2.

Я скопировал полученный a.out на мой iPhone и выполнил его.

Если кому-то интересен код ассемблера, сгенерированный этим:

  .section __TEXT,__text,regular,pure_instructions .section __TEXT,__textcoal_nt,coalesced,pure_instructions .section __TEXT,__const_coal,coalesced .section __TEXT,__picsymbolstub4,symbol_stubs,none,16 .section __TEXT,__StaticInit,regular,pure_instructions .syntax unified .section __TEXT,__text,regular,pure_instructions .globl _main .align 2 .code 16 .thumb_func _main _main: push {r7, lr} mov r7, sp sub sp, #20 movw r0, #65535 movt r0, #32767 movs r1, #0 movt r1, #0 str r1, [sp, #16] str r1, [sp, #12] ldr r1, [sp, #12] ldr r2, [sp, #12] cmp r2, r0 movw r0, #0 it gt movgt r0, #1 and r0, r0, #1 ldr r2, [sp, #12] cmn.w r2, #-2147483648 movw r2, #0 it lt movlt r2, #1 and r2, r2, #1 mov r3, sp str r2, [r3, #4] str r0, [r3] mov.w r2, #-2147483648 mvn r3, #-2147483648 movw r0, :lower16:(L_.str-(LPC0_0+4)) movt r0, :upper16:(L_.str-(LPC0_0+4)) LPC0_0: add r0, pc blx _printf ldr r1, [sp, #16] str r0, [sp, #8] mov r0, r1 add sp, #20 pop {r7, pc} .section __TEXT,__cstring,cstring_literals L_.str: .asciz "ival: %li, min: %i, max: %i, too big: %i, too small: %i\n" .subsections_via_symbols 

Это ошибка. В стандарте C нет места для too small чтобы быть чем-то другим, кроме 0. Вот как это работает:

  1. Поскольку INT_MIN является int , он преобразуется в long во время «обычных арифметических преобразований». Это происходит потому, что long имеет более высокий ранг, чем int (и оба являются подписанными типами). Никаких рекламных акций не происходит, поскольку все операнды имеют по крайней мере int rank. Не вызывается неопределенное поведение или поведение, указанное в реализации.

  2. Во время преобразования значение INT_MIN сохраняется. Поскольку он преобразуется из int в long , и гарантировано, что он имеет long , по крайней мере, интервала int , значение INT_MIN должно сохраняться во время преобразования. Не вызывается неопределенное поведение или поведение, указанное в реализации. Модульные преобразования не допускаются, только для неподписанных типов.

  3. Результатом сравнения должно быть 0 .

Нет места для маневра для расширения знака или других подобных вещей. Кроме того, поскольку вызов printf верен, проблем нет.

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

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

  • GCC 4.0, PPC + PPC64
  • GCC 4.2, PPC + PPC64
  • GCC 4.3, x64
  • GCC 4.4, x64
  • Clang 3.0, x64

Что это печатает?

 #include  printf("%016ld\n", LONG_MAX); long l_int_min = (long)INT_MIN; printf("%016lx\n", l_int_min); 

Мне интересно, будет ли INT_MIN принуждаться long не будучи расширенным. Это сделало бы 0 меньше результирующего значения.

EDIT: хорошо, результат первого printf() был 0000002147483647 , что означает, что на этой платформе 32-бит long , как и int . Так что литье int до long не должно ничего менять.

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