Add documentation and tests for 'a'/'A' printf conversions.

This commit is contained in:
Stephen Heumann 2023-04-16 20:25:15 -05:00
parent 2974c1b4bb
commit 3a298ec341
3 changed files with 152 additions and 2 deletions

View File

@ -26,6 +26,7 @@
{1} c99pragma.c
{1} c99inline.c
{1} c99desinit.c
{1} c99printfa.c
{1} c11generic.c
{1} c11align.c
{1} c11noret.c

View File

@ -0,0 +1,143 @@
/*
* Test 'a' and 'A' conversions in printf (C99).
*
* This makes certain assumptions about implementation-defined
* behavior like the positioning of bits in hex float output.
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void) {
char buf[100];
snprintf(buf, sizeof(buf), "%.15La %0.10LA", 123.0L, -234.0L);
if (strcmp(buf, "0xf.600000000000000p+3 -0XE.A000000000P+4"))
goto Fail;
snprintf(buf, sizeof(buf), "% 10.15La", 123.0L);
if (strcmp(buf, " 0xf.600000000000000p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%+ 25.15La", 123.0L);
if (strcmp(buf, " +0xf.600000000000000p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%.0La %#.0La", 123.0L, 123.0L);
if (strcmp(buf, "0xfp+3 0xf.p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%10.0La", 123.0L);
if (strcmp(buf, " 0xfp+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%0#10.0La", 123.0L);
if (strcmp(buf, "0x000f.p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%-010.0La", 123.0L);
if (strcmp(buf, "0xfp+3 "))
goto Fail;
snprintf(buf, sizeof(buf), "%La", 0xf.abcdef012345678p-16000L);
if (strcmp(buf, "0xf.abcdef012345678p-16000"))
goto Fail;
snprintf(buf, sizeof(buf), "%30La", -0xf.abcdef012345678p+16000L);
if (strcmp(buf, " -0xf.abcdef012345678p+16000"))
goto Fail;
snprintf(buf, sizeof(buf), "%.15A", -0.0);
if (strcmp(buf, "-0X0.000000000000000P+0"))
goto Fail;
snprintf(buf, sizeof(buf), "%010A", -INFINITY);
if (strcmp(buf, " -INF"))
goto Fail;
snprintf(buf, sizeof(buf), "%A", NAN);
if (!strstr(buf, "NAN"))
goto Fail;
snprintf(buf, sizeof(buf), "%LA", (long double)LDBL_MAX);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFFP+16380"))
goto Fail;
#ifdef __ORCAC__
snprintf(buf, sizeof(buf), "%.10LA", -(long double)LDBL_MAX);
if (strcmp(buf, "-0X8.0000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", (long double)LDBL_MAX);
if (strcmp(buf, "0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF8P+16380L);
if (strcmp(buf, "0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
snprintf(buf, sizeof(buf), "%.6LA", 0XF.1234567p-50L);
if (strcmp(buf, "0XF.123456P-50"))
goto Fail;
snprintf(buf, sizeof(buf), "%.6LA", 0XF.1234568p+500L);
if (strcmp(buf, "0XF.123456P+500"))
goto Fail;
snprintf(buf, sizeof(buf), "%.6LA", -0XF.1234569p+5000L);
if (strcmp(buf, "-0XF.123457P+5000"))
goto Fail;
fesetround(FE_UPWARD);
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", -0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "-0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
fesetround(FE_DOWNWARD);
snprintf(buf, sizeof(buf), "%.14LA", -0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "-0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
fesetround(FE_TOWARDZERO);
snprintf(buf, sizeof(buf), "%.14LA", -0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "-0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
fesetround(FE_TONEAREST);
snprintf(buf, sizeof(buf), "%La", (long double)0x1p-16445);
if (strcmp(buf, "0x0.000000000000002p-16386"))
goto Fail;
#endif
printf ("Passed Conformance Test c99printfa\n");
return 0;
Fail:
printf ("Failed Conformance Test c99printfa\n");
}

View File

@ -555,7 +555,9 @@ Generic selection expressions are primarily useful within macros, which can give
23. (C11) Character constants and string literals may now have prefixes indicating they should use Unicode encodings. The prefixes u8, u, and U indicate UTF-8, UTF-16, and UTF-32 encodings, respectively. The u8 prefix may only be used on string literals. The U and u prefixes may be used on string literals or character constants. U- and u-prefixed character constants have the types char32_t and char16_t (as defined in <uchar.h>); U- and u-prefixed string literals are treated as arrays of those types. For example, the string literal U"abc" designates an array with four members of type char32_t: the three letters encoded in UTF-32, plus a null terminator.
24. (C99) Floating-point constants may now be expressed in a hexadecimal format. These consist of a leading 0X or 0x, followed by a sequence of hexadecimal digits optionally containing a period, then P or p, then an exponent expressed as a sequence of decimal digits optionally preceded by + or -. These designate the number given by the hexadecimal digit sequence (with any digits after the period being the fractional part) multiplied by 2 raised to the specified exponent. For example, the constant 0xF.8p-1 is equivalent to 7.75. Note that ORCA/C currently only supports this hexadecimal floating-point format in C source code, not as an input or output format for any library functions.
24. (C99) Floating-point constants may now be expressed in a hexadecimal format. These consist of a leading 0X or 0x, followed by a sequence of hexadecimal digits optionally containing a period, then P or p, then an exponent expressed as a sequence of decimal digits optionally preceded by + or -. These designate the number given by the hexadecimal digit sequence (with any digits after the period being the fractional part) multiplied by 2 raised to the specified exponent. For example, the constant 0xF.8p-1 is equivalent to 7.75.
Note that the fprintf family of functions also support output in this hexadecimal floating-point format using the 'A' and 'a' conversion specifiers, described below. However, the hexadecimal floating-point format is currently not supported as an input format for any library functions.
25. (C99) When a function parameter is declared with an array type, type qualifiers and/or the keyword "static" may be included within the angle brackets that designate the array type. For example, a function may be defined as:
@ -927,7 +929,11 @@ These functions are equivalent to scanf, fscanf, and sscanf, except that the var
The length modifiers 'z', 't', 'j', 'hh', and 'll' are now allowed in the format strings for the fprintf and fscanf families of functions. They may be used with the 'd', 'i', 'o', 'u', 'x', 'X', or 'n' conversion specifiers. These each correspond to integer types, as follows: 'z' to size_t or the corresponding signed integer type, 't' to ptrdiff_t or the corresponding unsigned integer type, 'j' to intmax_t or uintmax_t, 'hh' to signed char or unsigned char, and 'll' to long long or unsigned long long. The corresponding argument must be an integer of an appropriate type, or a pointer to such an integer, as appropriate for the function and conversion specifier.
The conversion specifiers 'F', 'a', and 'A' are now allowed in the format strings for the fscanf family of functions. These are all equivalent to 'f' (but none of them accept numbers in the hexadecimal format allowed by C99). The 'F' conversion specifier is also now allowed in the format strings for the fprintf family of functions. It is equivalent to 'f', except that "INF" and "NAN" are guaranteed to be printed in upper case. The conversion specifiers 'a' and 'A' (both also used with floating-point numbers) are also recognized in the format strings for the fprintf family of functions, but they do not currently print the numbers in the hexadecimal format required by the C99 standard.
The conversion specifiers 'a' and 'A' are now allowed in the format strings for the fprintf family of functions. The 'a' specifier consumes an argument of type double or long double and writes the value in a hexadecimal exponential format. It consists of a leading sign (if negative or required by the flags used), then '0x', then a number in hexadecimal format (with one hexadecimal digit for the integer part, then a dot and fractional digits), then 'p', then a signed decimal number giving the exponent of 2. If a precision is specified, it gives the number of digits after the dot; if not, enough digits are used to exactly represent the number. If the precision is 0 and the '#' flag is not used, no dot is printed. The 'A' specifier is equivalent to 'a', except that all letters are output in upper case.
The conversion specifier 'F' is now allowed in the format strings for the fprintf family of functions. It is equivalent to 'f', except that "INF" and "NAN" are guaranteed to be printed in upper case.
The conversion specifiers 'F', 'a', and 'A' are also allowed in the format strings for the fscanf family of functions. These are all equivalent to 'f' (but none of them accept numbers in the hexadecimal format described above).
The ORCA/C-specific conversion specifier 'P' is now allowed in the format strings for the fprintf and fscanf families of functions. This works exactly the same as the existing 'b' conversion specifier, printing or reading input to a string with a leading length byte (a p-string). This new specifier was introduced because the 'b' specifier may be used for a different purpose in future C standards. For the time being, the 'b' specifier is still available with its existing meaning, but it is considered deprecated. Code should be migrated to use the 'P' conversion specifier instead.