Переполнение беззнакового символа в C ++ - PullRequest
0 голосов
/ 23 февраля 2020

Я нашел следующий фрагмент кода здесь https://www.toptal.com/c-plus-plus/interview-questions с вопросом: Сколько раз выполнит этот l oop? Объясните свой ответ

unsigned char half_limit = 150;

for (unsigned char i = 0; i < 2 * half_limit; ++i)
{
    // do something;
}

Ответ бесконечен.

Выражение 2 * half_limit будет преобразовано в int (основанное на правилах преобразования C ++) и будет иметь значение 300. Однако, поскольку я - беззнаковый символ, он представлен 8-битным значением, которое после достижения 255 переполнится (поэтому оно будет go обратно к 0), и поэтому цикл будет go навсегда.

Я угадал 45 раз (300-255), потому что я помню, что если вы увеличите счетчик целых чисел без знака, то счетчик снова начнет работать с 0, когда он переполнится. Итак, он преобразуется из целого числа в беззнаковый символ, почему его тогда не 255?

Спасибо

Ответы [ 4 ]

4 голосов
/ 23 февраля 2020

почему тогда не 255?

Поскольку 255 меньше 300. На следующей итерации i будет 0, что также меньше 300. Нет числа, представляемого 8 битовое целое число может достигать 300.


Технически, правильный ответ заключается в том, что количество итераций зависит от размера unsigned char. В системе, которая использует 16-битный байт, проблем не будет.

Другая проблема с ответом состоит в том, что «бесконечные» циклы не допускаются в языке, если в l * 1031 не предприняты определенные действия * - например, генерация некоторого результата. Так что на самом деле пример программы имеет неопределенное поведение (при условии 8-битного байта). Цитата из стандарта:

[intro.progress]

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

  • terminate ,
  • сделать вызов функции ввода-вывода библиотеки,
  • выполнить доступ через энергозависимое значение glvalue, или
  • выполнить операцию синхронизации или операцию atomi c .

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

3 голосов
/ 23 февраля 2020

Arithmeti c для типов, меньших int, сначала переводит их в int. По этой причине 2 * half_limit равно 300. Предполагая, что наибольшее значение, которое может представлять unsigned char, равно 255, все значения i могут иметь значение i < 2 * half_limit, таким образом, это бесконечное значение l oop.

1 голос
/ 23 февраля 2020
2 * half_limit

совпадает с:

int(2) * int(half_limit)

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

i < 2 * half_limit

становится

i < int(300)

, где меня переводят в int для фактического сравнения, но, поскольку я - беззнаковый символ, он никогда не может быть больше 255 (при условии, что наши беззнаковые символы равны 8 битам), поэтому это сравнение действительно:

int(smaller than 256) < int(300)

, что, конечно, всегда верно.

0 голосов
/ 23 февраля 2020
#include <iostream>

int main(int argc,char* argv[]){

    unsigned char half_limit = 150;

    for (unsigned char i = 0; i < 2 * half_limit; ++i)
    {
        printf("%.2X\n", i);
    }
}

скомпилировал этот код с помощью mingw g ++. дал мне бесконечное l oop, вывод значения шестнадцатеричного значения i показывает, что он сбрасывается каждый раз при переполнении. И, возможно, когда он переполняется, он устанавливает флаг. Поправьте меня, если я ошибаюсь

...