I'm working through K&R Second Edition, and can't figure out why I'm getting a certain result. The problem I'm solving is calculating upper and lower limits for data types. Specifically:
"Write a program to determine the ranges of char , short , int , and long variables, both signed and unsigned , by printing appropriate values from standard headers and by direct computation. Harder if you compute them: determine the ranges of the various floating-point types."
I've learned about bitwise operators and two's compliment, and have a solution I think should work for signed data types, but instead it's working for unsigned data types which doesn't make any sense to me. Here's the code:
#include <stdio.h>
main()
{
signed int i;
i = ~0;
i >>= 1;
printf("Upper limit: %d\n", i);
printf("Lower limit: %d\n", -i -1);
}
This will result in -1 being printed for the upper limit, and 0 printed for the lower limit. However, if I change i to an unsigned int, I get the result I was expecting (2147483647 and -2147483648). I can't wrap my head around this, because my understanding is that an unsigned int can never be less than 0, and a signed int should work using these bitwise operators, ie, if it's a 32 bit system,
~0 == 11111111111111111111111111111111
, and
~0 >> 1 == 011111111111111111111111111111111,
or 2147483647.
Any idea where I'm going wrong?
Write a C program to find the range of data types using the c library and without it. In this programming language, all the range information, such as the minimum and maximum constants, will be within the limits and float header files. The limits.h header file has information about integers and characters.
Data Types in C Data Type Memory (bytes) Range Format Specifier short int 2 -32,768 to 32,767 %hd unsigned short int 2 0 to 65,535 %hu unsigned int 4 0 to 4,294,967,295 %u int 4 -2,147,483,648 to 2,147,483,647 %d 9 more rows ...
The range of data types can be found by manually or using <limits.h> and <float.h> The size of data types in C is dependent on the compiler or you can say that the system architecture i.e. 32-bit compiler or 64-bit compiler. The size of data type int is 2 byte in 32-bit architecture or 4 bytes in 64-bit architecture.
C++ program for printing the range data type like int, char, short. METHOD 1.) calculate total number of bits by multiplying sizeof with 8 (say n) 2.) Calculate -2^ (n-1) for minimum range 3.) Calculate (2^ (n-1))-1 for maximum range
by using %d
you treat your value as signed
to proceed by printf
.
you may use %u
instead.
added
As Magn3s1um pointed out you don't need to specify signed
and unsigned
for your particular task printf
will make all job for you.
Output:
Note:
“In the expression i >>= 1
, a negative value is shifted right. The C standard says this is an implementation-defined operation, and many implementations define it to be arithmetic shift. In an arithmetic shift, the most significant bit is unchanged (keeps MSB (signed bit) = 1
)".
(you can read: Right shifting negative numbers in C that >>
is compiler dependent whether its singed or unsinfed shift, but probably in your case its doing an Arithmetic Shift.)
For this reason after code:
i = ~0;
i >>= 1;
i
remains ~0
. that is in binary == 11111111111111111111111111111111
.
And because ~0
== 11111111111111111111111111111111
is == 2'c complement of 1
that is -1
.
So when you prints with format string %d
it print -1
. You should use %u
to print max unsigned value that is == ~0
.
Important to note here:
§6.2.6.2 Language 45, ©ISO/IEC ISO/IEC 9899:201x
(ones’ complement). Which of these applies is
implementation-defined
, as is whether the value with sign bit1
and all value bits zero (for the first two), or with sign bit and all value bits 1 (for ones’ complement), is a trap representation or a normal value. In the case of sign and magnitude and ones’ complement, if this representation is a normal value it is called a negative zero.
Your understanding that :
~0 >> 1 == 011111111111111111111111111111111
is wrong! (it may be but not happening in your system, according to output)
~0 >> 1 == 111111111111111111111111111111111
, note MSB(signed bit) is 1
.
For unsigned shift, try following:
~0U >> 1 == 011111111111111111111111111111111
Notice Suffix U
for unsigned.
Second printf:
Because i
is -1
, So in second expression -i - 1
== - (-1) - 1
== 1 - 1
== 0
so output is zero : 0
.
Your compiler implements >> as arithmetic shift. Therefore, the MSB keeps it value of 1 and the shift does nothing.
That is, ~0 >> 1 is still ~0 because the shift sign-extends.
See here: https://stackoverflow.com/a/7632/1974021
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With