Use of the %a or %A conversion specifiers has unspecified behavior when used on non-normalized floating-point numbers.
According to ISO/IEC 9899:TC3 §7.19.6.1:
A double argument representing a floating-point number is converted in the
style ?0xh.hhhh p±d, where there is one hexadecimal digit (which is
nonzero if the argument is a normalized floating-point number and is
otherwise unspecified) before the decimal-point character (ISO/IEC 9899:TC3 §7.19.6.1)
Relying on the %a and %A specifiers to not produce values with a leading zero is error prone.
...
This noncompliant code relies on the %a specifier to produce a result starting with 0x1. or -0x1.
This behavior is guaranteed only for normalized numbers, but may fail for non-normalized values.
| Code Block | ||
|---|---|---|
| ||
#include <stdio.h>
#include <string.h>
/* Return the index of the first non-zero hexadecimal
double in the string line. Return NULL if there is
no double is present in line. */
static char *findHexDouble(char *line) {
char *index1 = strstr(line, "-0x1.");
char *index2 = strstr(line, "0x1.");
if (index1 == NULL && index2 == NULL) {
return NULL;
}
else if (index1 == NULL) {
return index2;
}
return (index1 < index2) ? index1 : index2;
}
static void printDouble(double val) {
char buf[64];
char *convertedDouble;
sprintf(buf, "%.8a", val);
convertedDouble = findHexDouble(buf);
if (convertedDouble != NULL) {
printf("%e is a double\n", val);
}
else {
printf("%e is not a double\n", val);
}
}
int main(void) {
double tiny = 0x1.0p-1020;
intsize_t i;
for (i = 0; i < 6; i++) {
printDouble(tiny);
tiny /= 2;
}
}
|
Implementation Specific
On a 32-bit Linux machine using GCC 4.3.2 this code produces the following output
...