Можем ли мы сдвинуть значение влево через некоторое время l oop? - PullRequest
0 голосов
/ 05 апреля 2020

Я пытаюсь использовать сдвиг влево, чтобы определить сетбит с помощью счетчика. Когда я попытался сдвинуть левую переменную var, я обнаружил, что она застряла в бесконечном l oop и печатается только ноль. Что не так со следующим кодом? Является ли законным даже использование левого сдвига в течение некоторого времени l oop?

#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv)
{
    int var =1;

    while(var<INT_MAX)
    {   
        var = var<<1;
        printf("%d\n", var);        
    }

    return 0;
}

Ответы [ 2 ]

3 голосов
/ 05 апреля 2020

Совершенно нормально использовать операцию сдвига внутри oop. Проблема с вашим кодом состоит в том, что var никогда не будет равным или большим как INT_MAX.

. Для лучшего понимания позвольте мне объяснить проблему с 8-битным знаковым целым числом, а не с 32-битным целым числом со знаком.

Вы начинаете со значения var = 00000001b (b указывает, что это двоичное число), а INT_MAX для 8-разрядного целого числа со знаком будет INT_MAX = 01111111b = 127 (обратите внимание, что старший бит равен 0, это потому, что это бит знака)

Теперь, если вы ушли влево var, вы медленно сдвигаете этот сингл 1 вправо

var << 1 = 00000010b =    2
var << 2 = 00000100b =    4
var << 3 = 00001000b =    8
var << 4 = 00010000b =   16
var << 5 = 00100000b =   32
var << 6 = 01000000b =   64
var << 7 = 10000000b = -128
var << 8 = 00000000b =    0
var << 9 = 00000000b =    0
...

После седьмого сдвига 1 бит достиг максимального бита, но так как у нас есть 8-битовое целое число со знаком, мы интерпретируем 10000000b не как 128, а как -128, и поэтому var < INT_MAX всегда будет истинным.

Если вы не Чтобы не знать, почему это происходит, вы можете прочитать два дополнения числа.

Редактировать: Более формально, как указал Эндрю Хенле: смещение значения за пределы диапазона его тип не определен. Результат операции x << y должен быть равен x * 2^y, а если x * 2 ^y не представлен типом, результат не определен.

Таким образом, приведенная выше таблица больше похожа на

var << 1 = 00000010b =      2
var << 2 = 00000100b =      4
var << 3 = 00001000b =      8
var << 4 = 00010000b =     16
var << 5 = 00100000b =     32
var << 6 = 01000000b =     64
var << 7 = undef.    = undef.
var << 8 = undef.    = undef.
var << 9 = undef.    = undef.
...
2 голосов
/ 05 апреля 2020

В этом l oop

while(var<INT_MAX)
{   
    var = var<<1;
    printf("%d\n", var);        
}

var никогда не может быть равно INT_MAX, потому что в нем установлен только один бит

int var = 1;

смещено.

Попробуйте следующее l oop:

while(var<INT_MAX)
{   
    var = ( var << 1 ) + 1;
    printf("%d\n", var);        
} 

Вот демонстрационная программа, в которой для простоты вместо подписанного типа int используется подписанный тип подписанного символа.

#include <stdio.h>
#include <limits.h>

int main(void) 
{
    signed char var = 1;

    while ( var  < SCHAR_MAX )
    {   
        var = ( var << 1 )  + 1;
        printf( "%d\n",  var );        
    }

    return 0;
}

Выход программы:

3
7
15
31
63
127

И в соответствии со стандартом C (5.2.4.2.1 Размеры целочисленных типов <limits.h>)

— maximum value for an object of type signed char
SCHAR_MAX +127 // 2^7 − 1
...