Search code examples
cencodingbinarydoubleieee-754

Why doesn't my manually entered double value match the expected value in C?


Question:

As a beginner, i am curious about memory architecture and how values get stored in memory, so I tried this code. Nothing else.

I'm trying to manually input byte values to create a specific double value using scanf in C. However, the resulting double value doesn't match my expectations. Here is what I'm doing:

First, the working example:

This program prints each byte value from the 8 bytes allocated to a double.

#include <stdio.h>

int main() {
    double a = 18446744073709551616.0;
    printf("value=%lf\n", a);
    int i;
    char *b = (char*)&a;
    for (i = 0; i < 8; i++) {
       printf("%d byte (%p)value: <%d>\n", i + 1, b, *b);
       b++;
    }
    return 0;
}

Output:

value=18446744073709551616.000000
1 byte (0x7ffda3f173f8)value: <0>
2 byte (0x7ffda3f173f9)value: <0>
3 byte (0x7ffda3f173fa)value: <0>
4 byte (0x7ffda3f173fb)value: <0>
5 byte (0x7ffda3f173fc)value: <0>
6 byte (0x7ffda3f173fd)value: <0>
7 byte (0x7ffda3f173fe)value: <-16>
8 byte (0x7ffda3f173ff)value: <67>

This makes sense when you convert all these values to binary and read it in little endian format, which gives me the IEEE-754 standard representation of

18446744073709551616.000000 conversion is:

1st byte value (0) which in binary -> (00000000)
2nd byte value (0) which in binary -> (00000000)
3rd byte value (0) which in binary -> (00000000)
4th byte value (0) which in binary -> (00000000)
5th byte value (0) which in binary -> (00000000)
6th byte value (0) which in binary -> (00000000)
7th byte value (-16) which in binary -> (11110000)
8th byte value (67) which in binary -> (01000011)

Now, the problematic code:

I tried to input this value manually using scanf with the following code:

#include <stdio.h>

int main() {
    double a;
    int i;
    char *b = (char*)&a;
    for (i = 0; i < 8; i++) {
       printf("Enter %d byte value: ", i + 1);
       scanf("%d", b);
       b++;
    }
    printf("Final value: %lf\n", a);
    return 0;
}

Input:

1 byte value: 0
2 byte value: 0
3 byte value: 0
4 byte value: 0
5 byte value: 0
6 byte value: 0
7 byte value: -16
8 byte value: 67

Output:

Final value: 0.000000

Question:

Why doesn't this code produce the same double value as the first example? How can I correctly input the byte values to achieve the same double value?


Solution

  • You are using the wrong format specifier. In order to ensure that the input is read as a char, you need the %hhd. Specifically, your line scanf("%d", b); scans an integer and stores in a char type variable, making the behaviour undefined. Recall that int and char have different bytes. char is 1 byte and int is usually 4 (depending on the compiler)

    For completeness, the code and outputs are shown below:

    #include <stdio.h>
    
    int main() {
        double a;
        int i;
        char *b = (char*)&a;
        for (i = 0; i < 8; i++) {
           printf("Enter %d byte value: ", i + 1);
           scanf("%hhd", b);
           b++;
        }
        printf("Final value: %lf\n", a);
        return 0;
    }
    

    Output:

    /tmp/E9Olq2nOoS.o
    Enter 1 byte value: 0
    Enter 2 byte value: 0
    Enter 3 byte value: 0
    Enter 4 byte value: 0
    Enter 5 byte value: 0
    Enter 6 byte value: 0
    Enter 7 byte value: -16
    Enter 8 byte value: 67
    Final value: 18446744073709551616.000000