Search code examples
cpointersmemorybytebit

How does c language store int in memory?


#include <stdio.h>
#include <stdlib.h>

int main() {
    int *p_x = (int *)malloc(1 * sizeof(int));
    scanf("%d", p_x);

    for (int i = 0; i < 4; i++) {
        char *one_byte_slice = (((char *)(p_x)) + i);
        printf("slice : %d , value : %d\n", i, *one_byte_slice);
    }
    return 0;
}

When I entered positive values they seems understandable to me but for negative I don't understand it well.

For *p_x = 127:

127
slice : 0 , value : 127
slice : 1 , value : 0
slice : 2 , value : 0
slice : 3 , value : 0

p_x  --->  0111 1111
           0000 0000
           0000 0000
           0000 0000

For *p_x = 256:

256
slice : 0 , value : 0
slice : 1 , value : 1
slice : 2 , value : 0
slice : 3 , value : 0

p_x  --->  0000 0000
           0000 0001
           0000 0000
           0000 0000

For *p_x = -20:

-20
slice : 0 , value : -20
slice : 1 , value : -1
slice : 2 , value : -1
slice : 3 , value : -1

p_x  --->  1001 0100
           1000 0001
           1000 0001
           1000 0001

And for *p_x = -256:

-256
slice : 0 , value : 0
slice : 1 , value : -1
slice : 2 , value : -1
slice : 3 , value : -1

p_x  --->  0000 0000
           1000 0001
           1000 0001
           1000 0001

So how is it stored in memory for fixed point numbers is is stored in 2's complement or other way?


Solution

  • This is called low-endian encoding. The individual bit slices of the integer are stored from least significative to most significative in the consecutive byte cells. Your integer is represented in binary form as:

    0000 0000 0000 0000 0000 0000 0111 1111
    

    (where I have used a space to separate each group of four bits). Each byte is stored from the least significant group of eight bits to the most, in growing byte addresses, starting from the right above:

    Addr.  Value.
    0000: 0111 1111
    0001: 0000 0000
    0002: 0000 0000
    0003: 0000 0000
    

    There's another way to do it, which is called big-endian, which stores the bytes just in the reverse direction, and some machines do it:

    (Big-endian)
    Addr.  Value.
    0000: 0000 0000
    0001: 0000 0000
    0002: 0000 0000
    0003: 0111 1111
    

    There are other ways to do, but today's computers normally use one of these two.

    In the case of negative numbers, the solution consists in thinking that negative numbers and positive numbers are so that adding and subtrating can be done withou having to use an alternate circuitry. So numbers are divided in two halves and the ones with the most significant bit represent the negative ones... so numbers are represented (I'll use only four bits for brevity):

    1000: -8
    1001: -7
    1010: -6
    1011: -5
    1100: -4
    1101: -3
    1110: -2
    1111: -1
    0000: 0
    0001: 1
    0010: 2
    0011: 3
    0100: 4
    0101: 5
    0110: 6
    0111: 7
    

    With 32 bits the result is the same, but extended to 32 bits... this makes that all the small negative numbers have all the most significant bits equal to 1.

    1000 0000 0000 0000: -2147483648
    1000 0000 0000 0001: -2147483647
    ...
    1111 1111 1111 1101: -3
    1111 1111 1111 1110: -2
    1111 1111 1111 1111: -1
    0000 0000 0000 0000: 0
    0000 0000 0000 0001: 1
    ...
    0111 1111 1111 1100: 2147483644
    0111 1111 1111 1101: 2147483645
    0111 1111 1111 1110: 2147483646
    0111 1111 1111 1111: 2147483647
    

    in such a way that adding is jumping in the previous table downwards and subtracting going upwards. This is called two's complement encoding.