Этот цикл неявно приводит int к size_t?

Я столкнулся с ошибкой в ​​моей программе:

for (int i = 0; i < objArray.size() - 1; ++i)

В моем случае objArray.size () — это длинная длинная без знака, а пустой вектор минус 1 равен примерно 18 квинтиллионам. Мне было интересно, должен ли цикл на каждой итерации приводить int к unsigned long long? Я проверил сборку и, используя int, создает код, отличный от size_t, без оптимизаций, с указанием -O2 он генерирует точно такую ​​же сборку. Означает ли это, что это не неявное приведение?

Я не понимаю сборку, но сгенерированный код был:

test rcx, rcx
je .L32
add rdx, rax

а потом :

cmp rdx, rax
jne .L28

1

Решение

Это может быть вызвано оптимизацией компилятора. Стандарт c ++ говорит, что переполнение целочисленных типов со знаком не определено. В этом случае, i начинается в 0, Если предположить, что i не записывается в цикл, таким образом, компилятор может сделать вывод, что i >= 0, поскольку переполнение является неопределенным поведением и может быть сокращено.

Обычно для сравнения со знаком без знака значение со знаком должно быть преобразовано в тип без знака, следуя правилам, которые вы можете посмотреть здесь. Эти правила являются причиной предупреждений компилятора при сравнении типа со знаком и без знака (что приводит к путанице, например, -1 > 2U
правда). В этом случае это не имеет значения, хотя.

С предположением i >= 0 и подписанные типы с 2 дополнениями, компилятор может безопасно переосмыслить i как unsigned long long так как он знает, что знак-бит 0, Вот что показывает ваш сборочный вывод.

Теперь мы можем видеть, что действительно есть ошибка. предполагать objArray.size() - 1 делает не вписаться в положительный знак int, Это вызвало бы i переполнение, вызывая неопределенное поведение, что всегда является плохой новостью.

1

Другие решения

Давайте рассмотрим код
для (int i = 0; i < objArray.size () — 1; ++ я)

вы делаете сравнение между int и size_t. Размер () -1 — это нижний знак без знака, когда массив пуст и приводит к значению std :: numeric_limits :: max (). Сравнение будет подписано / не подписано и использует правила продвижения типа, как указано здесь Подписанные / неподписанные сравнения

0

По вопросам рекламы [email protected]