I have written a program to find number of bits on a given machine.
#include <stdio.h>
int int_size(void);
int main(int argc, char *argv[])
{
printf("%d\n", int_size());
return 0;
}
int int_size(void)
{
int count = 1;
int value = 1;
while (1)
{
value <<= 1;
if (value > 0)
{
count++;
}
else
{
break;
}
}
return count + 1;
}
Now idea behind this is as follows. On most of the systems, left most bit is 1 for negative numbers. So, I start with 1. If the system used 8 bits for storing an integer, then 1 would be represented as 0000 0001. I then go on left shifting this number and then check whether its positive. Now, when number becomes, 1000 0000, left most bit is 1 and this would be taken as a negative number on most systems. So, while loop is exited and I get the count for the bits. I have tried this program on 7 online C compilers and all return value 32. So an integer has 32 bits on these systems. Now, I still don’t know if my code is portable enough. Are there any machines that do not have left most bit as 1 for negative numbers ? I have come across three methods to store negative number. two’s complement, one’s complement and sign + magnitude. All three have left most bit 1 for negative numbers. So, this method should work on all systems.
>Solution :
Now, I still don’t know if my code is portable enough.
Your code has undefined behavior so the answer is: No
From C (draft) standard N1570:
The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with
zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo
one more than the maximum value representable in the result type. If E1 has a signed
type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is
the resulting value; otherwise, the behavior is undefined.
When your value
is at 230 and you do one more left shift, the result is 231 which isn’t representable in an int
. Therefore you end in the "otherwise, the behavior is undefined" part.
If you don’t want to use sizeof
then you can write a program using unsigned types and test for zero for detecting the overflow. You actually already do that so all you need is unsigned int value = 1;
and you are safe.
That will work because the standard says:
For each of the signed integer types, there is a corresponding (but different) unsigned
integer type (designated with the keyword unsigned) that uses the same amount of
storage (including sign information) …