Home > Back-end >  How to get the padding position of a long double value in C ?
How to get the padding position of a long double value in C ?

Time:05-28

The number of bits for the mantissa, exponent and sign of a long double value can be detected in the following way (supposing iec559):

template <typename T>
constexpr uint32_t bitsInExponent() 
{
    static_assert(std::numeric_limits<T>::is_iec559);
    return std::ceil(std::log2(std::numeric_limits<T>::max_exponent-std::numeric_limits<T>::min_exponent 1));
}
// outputs 15 for long double on my machine/compiler

template <typename T>
constexpr uint32_t bitsInMantissa() 
{
    static_assert(std::numeric_limits<T>::is_iec559);
    static_assert(std::numeric_limits<T>::radix == 2);
    return std::numeric_limits<T>::digits-1;
}
// outputs 63 for long double on my machine/compiler

template <typename T>
constexpr uint32_t bitsInSign() 
{
    return 1;
}

Consequently, the total number of bits for the long double is (on my machine and compiler) 79 (63 15 1), probably a IEEE-754 binary64 extended format.

However, the memory footprint of the long double (sizeof(long double)) is 16, thus 128 bits.

The padding of the float value (those 128-79, 49bits) seems to be at the higher bits on my machine with my compiler, and mostly filled with garbage.

My question is: Are those 1-63 bits always at the higher bits of the 128 bits?

In case the padding of the extended IEEE-754 binary-64 format is not guaranteed to be at the highest bits, how to detect where is the padding?

Try it: https://onlinegdb.com/doL6E7WYL

CodePudding user response:

The authoritative answer can only come from reading the ABI for your implementation.

However, if your long double is 80-bit extended precision, then you are almost certainly on x86, since AFAIK it's the only major architecture with hardware support for that format. In that case, unless you have a very unusual compiler with a very unusual ABI, the data is going to be in the low 10 bytes, with the padding in the high 6 bytes. The x87 load and store instructions don't account for the padding, which is a more recent innovation to provide better alignment, so they will expect a pointer to the 10-byte data itself. By putting the data at the low end of the 16 bytes, a long double * is a pointer to the data, and can be used directly with an x87 load or store. If it were anywhere else, every memory access to a long double would require adding the appropriate offset, which would be inefficient.

Non-x86 platforms usually implement long double in one of two ways:

  • Either it is just an alias for double (the C standard allows this), in which case it would normally be binary64 double precision with no padding, and sizeof(long double) == 8. MSVC on x86-64 does this too, and doesn't give you access to the hardware's 80-bit extended precision support.

  • Or, it is binary128 quadruple precision, in which case you have sizeof(long double) == 16 and again no padding.

  •  Tags:  
  • c
  • Related