Home > Enterprise >  int64_t stored in a void pointer and then cast to a double always ends up being 0.000
int64_t stored in a void pointer and then cast to a double always ends up being 0.000

Time:10-28

I am making a function that converts any number (int64_t, uint64_t, double and later also hex numbers) to a string. I wrote 3 working functions for them seperatly but now I am trying to put it in one function. I searched around a bit on how to do this in C (I am relatively new to C) and found out I can do this with void pointers. I need to do this without the C library because this is for a hobby OS I am making.

This is how I am currently doing the checks for what type of number it is:

const char* to_string(void* value)
{
    double val = *(double*)value;

    if (val == (int64_t)val) {
        return int_to_string((int64_t)val);
    }
    else
    {
        // double to string conversion.
    }
}

But when I put in an int64_t or uint64_t null pointer it always returns 0.00000, which I don't fully understand.

I have reproduced this issue in a really small code snippet:

#include <stdint.h>
#include <stddef.h>
#include <stdio.h>

int main(){

    int64_t testNum = 2390874;
    void* value = &testNum;
    double val = *(double*)value;
    printf("%f", val);
    return 0;
}

I was expecting to just see the number printed, but that was not the case. I suspect I made some beginner mistake because C is new to me. Help would be much appreciated, and let me know if you need more info.

CodePudding user response:

The value 2,390,874 is not represented in the double format by bits that encode the number 2,390,874 in the same way as an int64_t.

Here is some explanation of the sample code:

int64_t testNum = 2390874;

This says to encode 2,390,874 in the format used for int64_t and store it in memory reserved for testNum. Using hexadecimal to represent the bits, this puts 00 00 00 00 00 24 7B 5A in memory.

void* value = &testNum;

This says to take the address of the memory reserved for testNum, convert it to void *, and store it in value.

double val = *(double*)value;

This says to convert the address in value to double *, use it to access the memory, and interpret the bits there in the double format. Doing the reinterpretation this way is not defined by the C standard. However, I will explain what happens assuming your C implementation does it.

In the format most commonly used for double, IEEE-754 binary64, the first bit encode a sign (0 for , 1 for −), the next eleven bits encode an exponent and one bit of the significand, and the remaining 52 bits encode the rest of the significand. (The significand is the fraction portion of a floating-point number.)

In 00 00 00 00 00 24 7B 5A, the first bit is 0, so it encodes a sign. The next eleven bits are zero. This encodes the exponent −1022, meaning a scaling of 2−1022, and it also indicates the leading bit of the significand is 0. (The significand is the fraction portion of a floating-point representation.) The remaining bits, ending in 24 7B 5A, encode the significand 2,390,874•2−52. (The scaling 2−52 is built into the format.)

Thus the number encoded is 2−1022•2,390,874•2−52 = 2,390,874•2−1074, which is about 1.1812487069350•10−317.

When you format this with %f, it appears as “0.000000” because it is so small. If you format it with %.99f, it will appear as “1.18124870693504449006160973608001590543193999051572110682125774306312005276915307940719688096129009e-317” in a good C implementation.

In conclusion, you cannot test whether bits in memory represent an int64_t or double by examining the bits alone. The same bits encode different values in different types. Type information must be conveyed separately.

  • Related