Отзыв об анализе примера кода (безопасное кодирование) - PullRequest
5 голосов
/ 02 марта 2011

У меня есть фрагмент кода из задания, в котором я не уверен.Я уверен, что знаю ответ, но я просто хочу перепроверить с сообществом, если я кое-что забыл.Название в основном является безопасным кодированием, и вопрос заключается только в том, чтобы объяснить результаты.

int main() {
   unsigned int i = 1;
   unsigned int c = 1;
   while (i > 0) {
     i = i*2;
     c++;
   }
   printf("%d\n", c);
   return 0;
}

Я рассуждаю так:

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

Я совершенно уверен, что это причина, но я просто хочу перепроверить.Есть мнения?

Ответы [ 7 ]

5 голосов
/ 02 марта 2011

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

Последнее обязательно произойдет один раз, поскольку вы умножаете на 2 (четное число) на каждой итерации, и это приводит к тому, что нулевой бит вставляется справа (наименее значащий бит), поэтому после некоторого количества итераций все ненулевые биты будет «сдвинут из числа» и станет нулевым.

2 голосов
/ 02 марта 2011

Нет переполнения при работе со значениями без знака.Все вычисления выполняются по модулю (UINT_MAX + 1).

Итак, что происходит, так как при многократном умножении значения на 2 вы в конечном итоге переходите к нулю ... и ваш цикл останавливается

Предположим,для простоты этот беззнаковый имеет ширину 4 бита.

1 * 2 = 2 ==> 0b0010
2 * 2 = 4 ==> 0b0100
4 * 2 = 8 ==> 0b1000
8 * 2 = 0 ==> 0b0000
1 голос
/ 02 марта 2011

В случае signed integer самый левый бит устанавливает знак , поэтому диапазон значений, которые может иметь этот элемент типа, составляет от -2147483648 до 2147483647 .Чтобы получить отрицательное значение из положительного значения, вы делаете бит, обратный ко всем битам, и наоборот.

В случае unsigned integer, самый левый бит используется для хранения дополнительных значений.Таким образом, диапазон значений, который может иметь этот элемент типа, составляет от 0 до 4294967295 .

В двоичной форме, когда i=1; и вы только делаете i = i*2;, тогда значения, которые вы можете иметьв качестве значений:

1 // 1 in base 10
10 // 2 in base 10
100 // 4 in base 10
1000
10000
100000
1000000
10000000
100000000
1000000000
10000000000
100000000000
1000000000000
10000000000000
100000000000000
1000000000000000
10000000000000000
100000000000000000
1000000000000000000
10000000000000000000
100000000000000000000
1000000000000000000000
10000000000000000000000
100000000000000000000000
1000000000000000000000000
10000000000000000000000000
100000000000000000000000000
1000000000000000000000000000
10000000000000000000000000000
100000000000000000000000000000
1000000000000000000000000000000 // 1073741824 in base 10
10000000000000000000000000000000 // 2147483648 in base 10 

Теперь, если у вас есть цикл, подобный: while (i > 0) { и i действует, как описано выше, тогда он будет в бесконечном цикле, поскольку он никогда не будет равен 0.Переполнения произойдут, но ваша программа не будет тормозить - она ​​все еще будет работать.

В случае, если переменная i подписана (по умолчанию), вы получите вывод c=32 в виде целого числа 10000000000000000000000000000000 с оценкой -2147483648и это < 0.Однако в этом случае вы не знаете выходных данных.

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

В качестве дополнительного факта в Java нет неподписанных примитивов или классов неизменяемых чисел.В некоторых случаях их отсутствие может быть болезненным.Это определенно полезное ключевое слово.

1 голос
/ 02 марта 2011

значения без знака не переполняются; на самом деле они гарантированы и определены для обхода.

0 голосов
/ 02 марта 2011

Поскольку i - целое число без знака (0 - 255), я буду равен 0 после 8 итераций из-за двоичного округления.

0 голосов
/ 02 марта 2011

вы правы насчет переполнения, но беззнаковое целое является беззнаковым по причине (нет знакового бита, следовательно, беззнаковое, беззнаковое целое начинается с 0), поэтому оно будет переполнено до 0, если бы оно было без знака, оно было бы переполнено на отрицательное число (- 2 ** 31 на 32-битной машине, например)

0 голосов
/ 02 марта 2011

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

...