2
0

test_sprintf.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #define USE_STB 1
  2. #if USE_STB
  3. # include "stb_sprintf.h"
  4. # define SPRINTF stbsp_sprintf
  5. # define SNPRINTF stbsp_snprintf
  6. #else
  7. # include <locale.h>
  8. # define SPRINTF sprintf
  9. # define SNPRINTF snprintf
  10. #endif
  11. #include <assert.h>
  12. #include <math.h> // for INFINITY, NAN
  13. #include <stddef.h> // for ptrdiff_t
  14. #include <stdio.h> // for printf
  15. #include <string.h> // for strcmp, strncmp, strlen
  16. #if _MSC_VER && _MSC_VER <= 1600
  17. typedef int intmax_t;
  18. typedef ptrdiff_t ssize_t;
  19. #else
  20. #include <stdint.h> // for intmax_t, ssize_t
  21. #endif
  22. // stbsp_sprintf
  23. #define CHECK_END(str) \
  24. if (strcmp(buf, str) != 0 || (unsigned) ret != strlen(str)) { \
  25. printf("< '%s'\n> '%s'\n", str, buf); \
  26. assert(!"Fail"); \
  27. }
  28. #define CHECK9(str, v1, v2, v3, v4, v5, v6, v7, v8, v9) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6, v7, v8, v9); CHECK_END(str); }
  29. #define CHECK8(str, v1, v2, v3, v4, v5, v6, v7, v8 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6, v7, v8 ); CHECK_END(str); }
  30. #define CHECK7(str, v1, v2, v3, v4, v5, v6, v7 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6, v7 ); CHECK_END(str); }
  31. #define CHECK6(str, v1, v2, v3, v4, v5, v6 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5, v6 ); CHECK_END(str); }
  32. #define CHECK5(str, v1, v2, v3, v4, v5 ) { int ret = SPRINTF(buf, v1, v2, v3, v4, v5 ); CHECK_END(str); }
  33. #define CHECK4(str, v1, v2, v3, v4 ) { int ret = SPRINTF(buf, v1, v2, v3, v4 ); CHECK_END(str); }
  34. #define CHECK3(str, v1, v2, v3 ) { int ret = SPRINTF(buf, v1, v2, v3 ); CHECK_END(str); }
  35. #define CHECK2(str, v1, v2 ) { int ret = SPRINTF(buf, v1, v2 ); CHECK_END(str); }
  36. #define CHECK1(str, v1 ) { int ret = SPRINTF(buf, v1 ); CHECK_END(str); }
  37. #ifdef TEST_SPRINTF
  38. int main()
  39. {
  40. char buf[1024];
  41. int n = 0;
  42. const double pow_2_75 = 37778931862957161709568.0;
  43. const double pow_2_85 = 38685626227668133590597632.0;
  44. // integers
  45. CHECK4("a b 1", "%c %s %d", 'a', "b", 1);
  46. CHECK2("abc ", "%-8.3s", "abcdefgh");
  47. CHECK2("+5", "%+2d", 5);
  48. CHECK2(" 6", "% 3i", 6);
  49. CHECK2("-7 ", "%-4d", -7);
  50. CHECK2("+0", "%+d", 0);
  51. CHECK3(" 00003: 00004", "%10.5d:%10.5d", 3, 4);
  52. CHECK2("-100006789", "%d", -100006789);
  53. CHECK3("20 0020", "%u %04u", 20u, 20u);
  54. CHECK4("12 1e 3C", "%o %x %X", 10u, 30u, 60u);
  55. CHECK4(" 12 1e 3C ", "%3o %2x %-3X", 10u, 30u, 60u);
  56. CHECK4("012 0x1e 0X3C", "%#o %#x %#X", 10u, 30u, 60u);
  57. CHECK2("", "%.0x", 0);
  58. #if USE_STB
  59. CHECK2("0", "%.0d", 0); // stb_sprintf gives "0"
  60. #else
  61. CHECK2("", "%.0d", 0); // glibc gives "" as specified by C99(?)
  62. #endif
  63. CHECK3("33 555", "%hi %ld", (short)33, 555l);
  64. #if !defined(_MSC_VER) || _MSC_VER >= 1600
  65. CHECK2("9888777666", "%llu", 9888777666llu);
  66. #endif
  67. CHECK4("-1 2 -3", "%ji %zi %ti", (intmax_t)-1, (ssize_t)2, (ptrdiff_t)-3);
  68. // floating-point numbers
  69. CHECK2("-3.000000", "%f", -3.0);
  70. CHECK2("-8.8888888800", "%.10f", -8.88888888);
  71. CHECK2("880.0888888800", "%.10f", 880.08888888);
  72. CHECK2("4.1", "%.1f", 4.1);
  73. CHECK2(" 0", "% .0f", 0.1);
  74. CHECK2("0.00", "%.2f", 1e-4);
  75. CHECK2("-5.20", "%+4.2f", -5.2);
  76. CHECK2("0.0 ", "%-10.1f", 0.);
  77. CHECK2("-0.000000", "%f", -0.);
  78. CHECK2("0.000001", "%f", 9.09834e-07);
  79. #if USE_STB // rounding differences
  80. CHECK2("38685626227668133600000000.0", "%.1f", pow_2_85);
  81. CHECK2("0.000000499999999999999978", "%.24f", 5e-7);
  82. #else
  83. CHECK2("38685626227668133590597632.0", "%.1f", pow_2_85); // exact
  84. CHECK2("0.000000499999999999999977", "%.24f", 5e-7);
  85. #endif
  86. CHECK2("0.000000000000000020000000", "%.24f", 2e-17);
  87. CHECK3("0.0000000100 100000000", "%.10f %.0f", 1e-8, 1e+8);
  88. CHECK2("100056789.0", "%.1f", 100056789.0);
  89. CHECK4(" 1.23 %", "%*.*f %%", 5, 2, 1.23);
  90. CHECK2("-3.000000e+00", "%e", -3.0);
  91. CHECK2("4.1E+00", "%.1E", 4.1);
  92. CHECK2("-5.20e+00", "%+4.2e", -5.2);
  93. CHECK3("+0.3 -3", "%+g %+g", 0.3, -3.0);
  94. CHECK2("4", "%.1G", 4.1);
  95. CHECK2("-5.2", "%+4.2g", -5.2);
  96. CHECK2("3e-300", "%g", 3e-300);
  97. CHECK2("1", "%.0g", 1.2);
  98. CHECK3(" 3.7 3.71", "% .3g %.3g", 3.704, 3.706);
  99. CHECK3("2e-315:1e+308", "%g:%g", 2e-315, 1e+308);
  100. #if __STDC_VERSION__ >= 199901L
  101. #if USE_STB
  102. CHECK4("Inf Inf NaN", "%g %G %f", INFINITY, INFINITY, NAN);
  103. CHECK2("N", "%.1g", NAN);
  104. #else
  105. CHECK4("inf INF nan", "%g %G %f", INFINITY, INFINITY, NAN);
  106. CHECK2("nan", "%.1g", NAN);
  107. #endif
  108. #endif
  109. // %n
  110. CHECK3("aaa ", "%.3s %n", "aaaaaaaaaaaaa", &n);
  111. assert(n == 4);
  112. #if __STDC_VERSION__ >= 199901L
  113. // hex floats
  114. CHECK2("0x1.fedcbap+98", "%a", 0x1.fedcbap+98);
  115. CHECK2("0x1.999999999999a0p-4", "%.14a", 0.1);
  116. CHECK2("0x1.0p-1022", "%.1a", 0x1.ffp-1023);
  117. #if USE_STB // difference in default precision and x vs X for %A
  118. CHECK2("0x1.009117p-1022", "%a", 2.23e-308);
  119. CHECK2("-0x1.AB0P-5", "%.3A", -0x1.abp-5);
  120. #else
  121. CHECK2("0x1.0091177587f83p-1022", "%a", 2.23e-308);
  122. CHECK2("-0X1.AB0P-5", "%.3A", -0X1.abp-5);
  123. #endif
  124. #endif
  125. // %p
  126. #if USE_STB
  127. CHECK2("0000000000000000", "%p", (void*) NULL);
  128. #else
  129. CHECK2("(nil)", "%p", (void*) NULL);
  130. #endif
  131. // snprintf
  132. assert(SNPRINTF(buf, 100, " %s %d", "b", 123) == 10);
  133. assert(strcmp(buf, " b 123") == 0);
  134. assert(SNPRINTF(buf, 100, "%f", pow_2_75) == 30);
  135. assert(strncmp(buf, "37778931862957161709568.000000", 17) == 0);
  136. n = SNPRINTF(buf, 10, "number %f", 123.456789);
  137. assert(strcmp(buf, "number 12") == 0);
  138. assert(n == 17); // written vs would-be written bytes
  139. n = SNPRINTF(buf, 0, "7 chars");
  140. assert(n == 7);
  141. // stb_sprintf uses internal buffer of 512 chars - test longer string
  142. assert(SPRINTF(buf, "%d %600s", 3, "abc") == 603);
  143. assert(strlen(buf) == 603);
  144. SNPRINTF(buf, 550, "%d %600s", 3, "abc");
  145. assert(strlen(buf) == 549);
  146. assert(SNPRINTF(buf, 600, "%510s %c", "a", 'b') == 516);
  147. // length check
  148. assert(SNPRINTF(NULL, 0, " %s %d", "b", 123) == 10);
  149. // ' modifier. Non-standard, but supported by glibc.
  150. #if !USE_STB
  151. setlocale(LC_NUMERIC, ""); // C locale does not group digits
  152. #endif
  153. CHECK2("1,200,000", "%'d", 1200000);
  154. CHECK2("-100,006,789", "%'d", -100006789);
  155. #if !defined(_MSC_VER) || _MSC_VER >= 1600
  156. CHECK2("9,888,777,666", "%'lld", 9888777666ll);
  157. #endif
  158. CHECK2("200,000,000.000000", "%'18f", 2e8);
  159. CHECK2("100,056,789", "%'.0f", 100056789.0);
  160. CHECK2("100,056,789.0", "%'.1f", 100056789.0);
  161. #if USE_STB // difference in leading zeros
  162. CHECK2("000,001,200,000", "%'015d", 1200000);
  163. #else
  164. CHECK2("0000001,200,000", "%'015d", 1200000);
  165. #endif
  166. // things not supported by glibc
  167. #if USE_STB
  168. CHECK2("null", "%s", (char*) NULL);
  169. CHECK2("123,4abc:", "%'x:", 0x1234ABC);
  170. CHECK2("100000000", "%b", 256);
  171. CHECK3("0b10 0B11", "%#b %#B", 2, 3);
  172. #if !defined(_MSC_VER) || _MSC_VER >= 1600
  173. CHECK4("2 3 4", "%I64d %I32d %Id", 2ll, 3, 4ll);
  174. #endif
  175. CHECK3("1k 2.54 M", "%$_d %$.2d", 1000, 2536000);
  176. CHECK3("2.42 Mi 2.4 M", "%$$.2d %$$$d", 2536000, 2536000);
  177. // different separators
  178. stbsp_set_separators(' ', ',');
  179. CHECK2("12 345,678900", "%'f", 12345.6789);
  180. #endif
  181. return 0;
  182. }
  183. #endif