I have this C code which tries to store a signed short
in signed char
.
signed char
range is [-128,127]
and signed short
range is [-32768, 32767]
.
signed char sChar = SCHAR_MAX;
printf("Signed Char: %d", sChar);
signed short sShort = SHRT_MAX;
printf("\nSigned Short: %d", sShort);
sChar = sShort;
printf("\nSigned Short to Signed Char: %d", sChar);
Output:
Signed Char: 127
Signed Short: 32767
Signed Short to Signed Char: -1
This what I think happens in background.
signed short in bits: 0111 1111 1111 1111 (32767)
signed char in bits: <discarded bits> 1111 1111 (-1)
Basically it copies all bits from right and discards the remaining. TL;DR It truncates short to store it in char thus we lose information.
Question starts here. Information above was to give background.
Lets say I give signed char
-1 and try to store it in signed short
. The value inside signed short
will be -1.
In binary if represent it would be:
signed char in bits: 1111 1111 (-1)
signed short in bits: 1111 1111 1111 1111 (32767)
My question is how does compiler assigns char to short in background? It is definitely not one to one bit copy like above. My guess is that it shifts the bits to the right and ones' compliment the remaining.
1111 1111 // Signed Char
1111 1111 0000 0000 // Shifting bits
1111 1111 1111 1111 // Ones' complimenting the right 8 bits
This isn't a complete and good answer because i want to sleep, But i think may help to you.
I will edit it soon.
Code
#include <stdio.h>
#include <limits.h>
#show bits
//https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format
void printbitsc( signed char x)
{
for(int i=sizeof(x)<<3; i; i--)
putchar('0'+((x>>(i-1))&1));
}
void printbitss( signed short x)
{
for(int i=sizeof(x)<<3; i; i--)
putchar('0'+((x>>(i-1))&1));
}
//https://www.geeksforgeeks.org/little-and-big-endian-mystery/
/* function to show bytes in memory, from location start to start+n*/
void show_mem_rep(char *start, int n)
{
int i;
for (i = 0; i < n; i++)
printf(" %.2x", start[i]);
printf("\n");
if (start[0]==0x67)
printf("little endian\n");
else
printf("big endian\n");
}
int main(int argc, char const *argv[]) {
int i = 0x01234567;
show_mem_rep((char *)&i, sizeof(i));
printf("%zu\n",sizeof (signed short));
printf("%zu\n",sizeof (signed char));
signed char sChar = SCHAR_MAX;
printf("Signed Char: %d\n", sChar);
printbitsc(sChar);
signed short sShort = SHRT_MAX;
printf("\nSigned Short: %d\n", sShort);
printbitss(sShort);
sChar = sShort;
printf("\nSigned Short to Signed Char: %d\n", sChar);
printbitsc(sChar);
signed char ssChar = SCHAR_MAX;
printf("Signed Char: %d\n", ssChar);
printbitsc(ssChar);
signed short ssShort = SHRT_MAX;
printf("\nSigned Short: %d\n", ssShort);
printbitss(ssShort);
ssShort=ssChar;
printf("\nSigned Short to Signed Char: %d\n", ssShort);
printbitsc(ssShort);
return 0;
}
In little endian data store inside memory on reverse order, i.e. 0x01: 1
value store in memory: 0x10:1111_0000:240
(change order of one and zero)
So in first case we face with a truncation case as
ss: 0111_1111_1111_1111
7 F F F
Inside memory we actually have: F F F 7
and for
sc: 0111_1111
7 F
In memory we actually have: F 7
Now by assignment first element of ss
memory i.e. FF
will truncate and placed on 16 bit sc
place.
F F -> F 7
Now we actually have in memory: 1111_1111
lets translate it to human readable number (i convert from twos complement to decimal)
first of all fist one means minus (1: -)
now we reach to :111_1111
by tracking conversion algorithm : minus [ not( 111_1111) + 1]
= minus[(000_0000)+1]
= minus [1] = -1
At last we reach to -1
on sc
variable.
In second case integer promotion will accrued.
sc: 0111_1111
7 F
Memory: F 7
ss: 0111_1111_1111_1111
7 F F F
Memory: F F F 7
We work with memory F7
wants to go inside FFF7
so F7
must be promoted to a 16 bits length by adding excess 0.
These zeroes added after first element and F7
changes to F700
.
Now the question is how F700
go to 16 bit length place.
F700 -> F F F 7
After that we face to F700
on a 16 bits length variable.
As we know F700
actually represents these bit pattern: 0000_0000_0111_1111
when we have read it with normal printf()
, its show 007F
.
By simple binary to decimal conversion 007F
equals to 127
.