Accessing a character from int variable using pointer in C - c

Why the output of below code is -127. Why shouldn't it be -1?
#include<stdio.h>
int main(){
int a = 129;
char *ptr;
ptr = (char *)&a;
printf("%d ",*ptr);
return 0;
}

If you will output the variable a in hexadecimal you will see that it is represented like 0x81.
Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
int a = 129;
printf( "%#x\n", a );
return 0;
}
Its output is
0x81
0x80 is the minimal value of an object of the type char if the type char behaves as the type signed char. This value is equal to the decimal value -128.
Here is another demonstrative program.
#include <stdio.h>
int main(void)
{
char c = -128;
printf( "%#hhx\n", c );
return 0;
}
Its output is
0x80
If to add 1 you will get the value -127.
The two's complement representation of the character value -1 looks in hexadecimal like 0xff. If to add 1 you will get 0.

It can be understood as follows:
We all know that the range of (signed) char is from [-128 to 127], now let's break this range into binary format, so, the bits required is 8 (1 Byte)
0 : 0000 0000
1 : 0000 0001
2 : 0000 0010
3 : 0000 0011
...
126 : 0111 1110
127 : 0111 1111 <-- max +ve number as after that we will overflow in sign bit
-128 : 1000 0000 <-- weird number as the number and its 2's Complement are same.
-127 : 1000 0001
-126 : 1000 0010
...
-3 : 1111 1101
-2 : 1111 1110
-1 : 1111 1111
So, now coming back to the question, we had int a = 129;, clearly 129 when stored inside the char data type it is going to overflow as the max positive permissible value is 127. But why we got -127 and not something else?
Simple, binary equivalent of 129 is 1000 0001 and for char data-type that comes somewhere around,
127 : 0111 1111
-128 : 1000 0000
-127 : 1000 0001<-- here!
-126 : 1000 0010
...
So, we get -127 when 129 is stored in it.

When you convert a signed char to int, what will be filled for left 24 bits?
The answer is not always '0', but the 'sign bit' -- highest bit -- .
You may interest the following demo code:
#include<stdio.h>
int main(){
int a = 129;
char *ptr;
ptr = (char *)&a;
// output "0x81", yes 129 == 0x81
printf("0x%hhx\n",*ptr);
// output 0xffffff81
int b = *ptr; // convert a 'signed char' to 'int'
// since the 'sign bit' of the char is 'minus', so left padding that much '1'
printf("0x%x\n",b);
unsigned char *ptru = (unsigned char *)&a;
b = *ptru;
printf("0x%x\n",b); // still, output "0x81"
return 0;
}

Related

Why data overflow in a `char` data type causes wrappping the value within its range?

I recently came across this question and the answer given by #chux - Reinstate Monica.
Quoting lines from their answer, "This is implementation-defined behavior. The assigned value could have been 0 or 1 or 2... Typically, the value is wrapped around ("modded") by adding/subtracting 256 until in range. 100 + 100 -256 --> -56."
Code:
#include <stdio.h>
int main(void)
{
char a = 127;
a++;
printf("%d", a);
return 0;
}
Output: -128
In most of the C compilers, char type takes 1 Byte size and strictly speaking, I'm assuming its 16-bit system and char takes 1 Byte.
When a = 127, its binary representation inside the computer is 0111 1111, increasing it with 1 should yield the value
0111 1111 + 0000 0001 = 1000 0000
which is equal to -0(considering, signed-number representation, where left-most bit represents 0 = + and 1 = -) then why the output is equal to -128?
Is it because of the "INTEGER PROMOTION RULE"? I mean, for this expression a + 1, a gets converted to int (2 Bytes) before the + operation and then its binary representation in the memory becomes 1111 1111 1000 0000 which is equal to -128 and makes sense to the output -128. But then this assumption of mine conflicts with the quoted lines of Chux-Reinstate-Monica about wrapping the values.
1000 0000 which is equal to -0...
Ones' complement has a -0, but most computers use two's complement which does not.
In two's complement notation the left-most bit represents -(coefficient_bit * 2^N-1) i.e. in your case, 1000 0000 the left-most bit represents -(1 * 2^8-1) which is equal to -128 and that's why the output is the same.
Your char is an 8 bit signed integer in which case 1000 0000 is -128. We can test what 1000 0000 is conveniently using the GNU extension which allows binary constants.
char a = 0b10000000;
printf("%d\n", a); // -128
char, in this implementation, is a signed 8-bit integer. Adding 1 to 127 causes integer overflow to -128.
What about integer promotion? Integer promotion happens during the calculation, but the result is still a char. 128 can't fit in our signed 8-bit char, so it overflows to -128.
Integer promotion is demonstrated by this example.
char a = 30, b = 40;
char c = (a * b);
printf("%d\n", c); // -80
char d = (a * b) / 10;
printf("%d\n", d); // 120
char c = (a * b); is -80, but char d = (a * b) / 10; is 120. Why? Shouldn't it be -8? The answer here is integer promotion. The math is done as native integers, but the result must still be stuffed into an 8-bit char. (30 * 40) is 1200 which is 0100 1011 0000. Then it must be stuffed back into an 8 bit signed integer; that's 1011 0000 or -80.
For the other calculation, (30 * 40) / 10 == 1200 / 10 == 120 which fits just fine.

difficulty understanding signed not

I'm having trouble understanding why c equals -61 on the following program:
main() {
unsigned int a = 60; // 60 = 0011 1100
unsigned int b = 13; // 13 = 0000 1101
int c = 0;
c = ~a; //-61 = 1100 0011
printf("Line 4 - Value of c is %d\n", c );
}
I do understand how the NOT operator works on 0011 1100 (the solution being 1100 0011). But I'm not sure why the decimal number is increased by 1. Is this some sort of type conversion from unsigned int (from a) into signed int (from c) ?
Conversion from a positive to a negative number in twos complement (the standard signed format) constitutes a bitwise inversion, and adding one.
Note that for simplicity I am using a single signed byte.
So if 60 = 0011 1100
Then c = 1100 0011 + 1
= 1100 0100
And for a signed byte, the most significant bit is negative,
so
c = -128 + 64 + 4 = -60
You need to add 1 to account for the fact that the most significant bit is -128, while the largest positive number is 0111 1111 = 127. All negative numbers have a 1 for -128 which needs to be offset.
This is easy to see when you look at converting 0 to -0. Invert 00000000 and you get 11111111 and adding one gets you back to 00000000. Do the same with 1 to -1 and you get 11111111 - the largest possible negative number.

how integer is promoted to unsigned integer

#include<stdio.h>
void main()
{
int a = -1;
unsigned int b =15;
if(b==a)
printf ("b is equal to a");
}
The output is empty. negative integers are stored as 2's complement of same postive number .When a integer is compared to unsigned int integer is promoted to unsigned int by considering the 2's complement as unsigned int which is 15 here but the output is empty eventhough the 2's complement of -1 is 15
The variable a and b
int a = -1; /* its a sign ed int, it takes 4 bytes */
unsigned int b =15;/* its a unsigned int */
And its looks like below
a = -1 => 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
b = 15 => 0000 0000 | 0000 0000 | 0000 0000 | 0000 1111
MSB LSB
Now when you compare a and b like
if(b==a) {
/* some code */
}
Here you are doing comparison == between two different types(a is of signed type & b is of unsigned type). So implicitly compiler will convert/promote sign int to unsigned int & then it will perform comparison ==. See this http://port70.net/~nsz/c/c11/n1570.html#6.3.1.8 for arithmetic conversation rules.
Now What is the unsigned equivalent of a or -1 ? Its all one's in 4 byte i.e 4294967295. So now it looks like
if(15==4294967295) { /*its false */
/* some code */
}
Since if condition is false, your code doesn't print anything.
If you change variable b to be
unsigned int b = 4294967295;
(This does assume int is being stored as 32 bits)
The print statement will run. See, https://stackoverflow.com/a/2084968/7529976

C printing char array as float

I'm trying to print a char array of 4 elements as a float number. The compiler(gcc) won't allow me to write z.s={'3','4','j','k'}; in the main() function, why?
#include <stdio.h>
union n{
char s[4];
float x;
};
typedef union n N;
int main(void)
{
N z;
z.s[0]='3';
z.s[1]='4';
z.s[2]='j';
z.s[3]='k';
printf("f=%f\n",z.x);
return 0;
}
The output of the program above is: f=283135145630880207619489792.000000 , a number that is much larger than a float variable can store; the output should be, in scientific notation, 4.1977085E-8.
So what's wrong?
z.s={'3','4','j','k'}; would assign one array to another. C doesn't permit that, though you could declare the second and memcpy to the first.
The largest finite value that a single-precision IEEE float can store is 3.4028234 × 10^38, so 283135145630880207619489792.000000, which is approximately 2.8313514 × 10^26 is most definitely in range.
Assuming your chars are otherwise correct, the knee-jerk guess would be that you've got your endianness wrong.
EDIT:
34jk if taken from left to right, as on a big-endian machine is:
0x33 0x34 0x6a 0x6b
= 0011 0011, 0011 0100, 0110 1010, 0110 1011
So:
sign = 0
exponent = 011 0011 0 = 102 (dec), or -25 allowing for offset encoding
mantissa = [1] 011 0100 0110 1010 0110 1011 = 11823723 / (2^23)
So the value would be about 4.2 × 10^-8, which is what you want.
In little endian:
0x6b 0x6a 0x34 0x33
= 0110 1011, 0110 1010, 0011 0100, 0011 0011
sign = 0
exponent = 110 1011 0 = 214 (dec) => 87
mantissa = [1]110 1010 0011 0100 0011 0011 = 15348787 / (2^23)
So the value would be about 2.8 * 10^26, which is what your program is outputting. It's a safe conclusion you're on a little endian machine.
Summary then: byte order is different between machines. You want to use your bytes the other way around — try kj43.
What you actually see is {'k' 'j' '4' '3'}

C bits shifting short ints

Why result of
include <stdio.h>
int main()
{
unsigned short int i = 0xff ;
unsigned short int j;
j= i<<2;
printf("%x n%x\n", i, j);
return 0;
}
is j = 3fc ?
if both i and j are short int - so they are 2bytes values, so j shouldnt =fc ??
thx in advance for explanations.
~
~
Shifting 0xff left two bits looks like this:
0000 0000 1111 1111
0 0 f f
0000 0011 1111 1100 -- Shifted left 2 bits.
0 3 f c
So 0x00ff << 2 = 0x03fc. Everything looks as it should be .
No, 0x3fc is correct. Note that a byte is two hex digits, so a (16-bit) short has a total of 4 hex digits.
0xff << 2 == 0xff * 4 == 0x3fc == 1020
Even if they are 2-bytes, they are allowed to hold this small value.
3FC requires only 12 bits to store so it can be stored in 2 bytes.
C++ makes no guarantee as to the number of bytes in an unsigned short int. It in fact makes almost no guarantee about the size of any type other than char which is guaranteed to be 1 byte.
In this case though it's irrelevant because 3fc can be successfully stored in only 2 bytes.
Maybe this is what you actually tried to write? (Remember an hex digit is 4 bits only, ie, half a byte)
#include <stdio.h>
int main()
{
unsigned short int i = 0xffff;
unsigned short int j;
j = i<<8;
printf("%x %x\n", i, j);
return 0;
}
This outputs ffff ff00

Resources