0

This loop runs infinitely though the value if shift operations becomes zero. Not sure why. Need clarifications.

size_t size_of_byte()
 {
  unsigned int size = 0, i = 1; 
  while((i << size) > 0)
   {
     size++;
   }
 printf("The size of a byte is %u",size);

 return size;
}
Makoto
  • 104,088
  • 27
  • 192
  • 230
Khanna
  • 59
  • 5
  • What language is this? C? C++? – Makoto Sep 10 '15 at 17:23
  • "though the value if shift operations becomes zero." - obviously: not. why don't you print it? – Karoly Horvath Sep 10 '15 at 17:37
  • the value becomes zero, but still the loop is running. Not sure it will check the value or it is checking if the operation is successful :( – Khanna Sep 10 '15 at 17:40
  • In fact, the debugger will display zero, but the real value used in the assembly code is never less than 1. – perror Sep 10 '15 at 17:41
  • This never becomes 0 hence the while never stops. – rbaleksandar Sep 10 '15 at 17:44
  • 1
    To fix the code you could change to `size = 1; while (i <<= 1) ++size;`. BTW this tells you the size of `unsigned int`, not of byte. And you could use the predefined macro `CHAR_BIT` to find this information out. – M.M Sep 10 '15 at 17:51
  • See also http://stackoverflow.com/questions/7401888/why-doesnt-left-bit-shift-for-32-bit-integers-work-as-expected-when-used – Karoly Horvath Sep 10 '15 at 17:53
  • 1
    `unsigned int != size_t`. And you never change the value of i – phuclv Sep 10 '15 at 17:56

2 Answers2

4

Looking for a betteer link, this is from C++, but the behaviour is the same.

http://en.cppreference.com/w/cpp/language/operator_arithmetic

if the value of the right operand is negative or is greater or equal to the number of bits in the promoted left operand, the behavior is undefined.

The compiler can assume you will never shift more than the width of that integer, consequently, the result will never be 0, so the check is not necessary. This is a perfectly legal optimization, you're relying on UB.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • You are definitely right, but the choice made by, both, `gcc` and `clang` (llvm) are quite strange. If somebody can explain it to me, I would be interested. – perror Sep 10 '15 at 17:45
  • What is wrong with my solution, I ran it and and the output came as 8 which is the size of byte, I am just curious. – Sumeet Sep 10 '15 at 17:47
  • Sir I am confused on part why it has **UB** . Can you please elaborate it ? – ameyCU Sep 10 '15 at 17:47
  • @ameyCU: in the code `size` is eventually going to be more (or equal:) than the number of bits, e.g. 32. – Karoly Horvath Sep 10 '15 at 17:49
  • @Dante.: It's UB, anything can happen. The problem will manifest if the compiler *does* the actual optimization (likely case) or if on the platform the result is not 0 (very unlikely). – Karoly Horvath Sep 10 '15 at 17:51
  • @KarolyHorvath Yeah that explains it . Thank You Sir !! :) – ameyCU Sep 10 '15 at 17:53
  • 1
    Does not this infinite while loop depend on `i = 1`. Had it been any other value, the loop would stop. – chux - Reinstate Monica Sep 10 '15 at 17:54
0

It is hard to see how your code would ever stop as you are shifting i to the left by size while increasing size. This will grow exponentially until overflow occurs and a crash. If I understand you are simply trying to determine the size of a byte with size_of_byte(), you are far better served actually checking the number of bits in 1-byte. By convention, storage for char is 1-byte, so if you wanted to prove to yourself that it really contained 8-bits, you would do something like:

/* return the number of bits-per-byte */
size_t szofbyte (void)
{
    unsigned char c = 0;
    unsigned char sz = 1;

    c = ~c; /* invert the bits of c */
    while ((c >>= 1)) sz++;

    return sz;
}

It may be instructive to visualize the bit operations involved. Simply adding a few printf statements and outputting the value of the variable you are testing in binary will show what is happening and why and how the loop completes as it should. Here is a short example with an annotated version of the function:

#include <stdio.h>

#ifndef BITS_PER_LONG
#define BITS_PER_LONG 64
#endif

size_t szofbyte_ann (void);
char *binpad (unsigned long n, size_t sz);

int main (void) {

    printf ("\n the size of a byte is : %zu bits\n\n", szofbyte_ann());

    return 0;
}

/* return the number of bits-per-byte (annotated) */
size_t szofbyte_ann (void)
{
    unsigned char c = 0;
    unsigned char sz = 1;

    c = ~c; /* invert the bits of c */
    printf ("\n sz : %hhu  c : %s\n", sz, binpad (c, 8));
    while ((c >>= 1)) {
        sz++;
        printf (" sz : %hhu  c : %s\n", sz, binpad (c, 8));
    }

    return sz;
}

/* return binary representation of 'n' paddded to 'sz' chars */
char *binpad (unsigned long n, size_t sz)
{
    static char s[BITS_PER_LONG + 1] = {0};
    char *p = s + BITS_PER_LONG;
    register size_t i;

    for (i = 0; i < sz; i++)
        *--p = (n>>i & 1) ? '1' : '0';

    return p;
}

Output

$ ./szofbyte

 sz : 1  c : 11111111
 sz : 2  c : 01111111
 sz : 3  c : 00111111
 sz : 4  c : 00011111
 sz : 5  c : 00001111
 sz : 6  c : 00000111
 sz : 7  c : 00000011
 sz : 8  c : 00000001

 the size of a byte is : 8 bits
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85