Avoid old-style casts

Replace C-style casts with static_cast/const_cast so -Wold-style-cast
is clean, and enable that warning in the Unix test builds and the
amalgamated-header CI job.
diff --git a/.github/workflows/amalgamate-ubuntu24.yml b/.github/workflows/amalgamate-ubuntu24.yml
index a7982d4..c2651fb 100644
--- a/.github/workflows/amalgamate-ubuntu24.yml
+++ b/.github/workflows/amalgamate-ubuntu24.yml
@@ -14,4 +14,4 @@
           python3 ./script/amalgamate.py > build/fast_float/fast_float.h &&
           cp tests/string_test.cpp build/ &&
           cd build &&
-          g++ string_test.cpp
+          g++ -Werror=old-style-cast string_test.cpp
diff --git a/benchmarks/bench_ip.cpp b/benchmarks/bench_ip.cpp
index 825a6b0..89e3a34 100644
--- a/benchmarks/bench_ip.cpp
+++ b/benchmarks/bench_ip.cpp
@@ -108,10 +108,10 @@
   buf.reserve(N * ip_size);
 
   for (size_t i = 0; i < N; ++i) {
-    uint8_t a = (uint8_t)dist(rng);
-    uint8_t b = (uint8_t)dist(rng);
-    uint8_t c = (uint8_t)dist(rng);
-    uint8_t d = (uint8_t)dist(rng);
+    uint8_t a = static_cast<uint8_t>(dist(rng));
+    uint8_t b = static_cast<uint8_t>(dist(rng));
+    uint8_t c = static_cast<uint8_t>(dist(rng));
+    uint8_t d = static_cast<uint8_t>(dist(rng));
     std::string ip_line = make_ip_line(a, b, c, d);
     ip_line.resize(ip_size, ' '); // pad to fixed size
     buf.append(ip_line);
@@ -127,7 +127,7 @@
   std::string buffer(ip_size * N, ' ');
 
   pretty_print(volume, bytes, "memcpy baseline", counters::bench([&]() {
-                 std::memcpy((char *)buffer.data(), buf.data(), bytes);
+                 std::memcpy(buffer.data(), buf.data(), bytes);
                }));
 
   pretty_print(volume, bytes, "just_seek_ip_end (no parse)",
@@ -138,7 +138,7 @@
                  int ok = 0;
                  for (size_t i = 0; i < N; ++i) {
                    const char *q = seek_ip_end(p, pend);
-                   sum += (uint32_t)(q - p);
+                   sum += static_cast<uint32_t>(q - p);
                    p += ip_size;
                  }
                  sink += sum;
diff --git a/benchmarks/bench_uint16.cpp b/benchmarks/bench_uint16.cpp
index c4cef81..a17db57 100644
--- a/benchmarks/bench_uint16.cpp
+++ b/benchmarks/bench_uint16.cpp
@@ -75,7 +75,7 @@
   buffer.reserve(N * 6); // up to 5 digits + delimiter
 
   for (size_t i = 0; i < N; ++i) {
-    uint16_t val = (uint16_t)dist(rng);
+    uint16_t val = static_cast<uint16_t>(dist(rng));
     expected.push_back(val);
     std::string s = std::to_string(val);
     buffer.append(s);
diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h
index 2748d65..ba6983b 100644
--- a/include/fast_float/ascii_number.h
+++ b/include/fast_float/ascii_number.h
@@ -32,7 +32,7 @@
 // able to optimize it well.
 template <typename UC>
 fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
-  return (unsigned)(c - UC('0')) <= 9u;
+  return static_cast<unsigned>(c - UC('0')) <= 9u;
 }
 
 fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
@@ -223,8 +223,8 @@
     return false;
   FASTFLOAT_SIMD_RESTORE_WARNINGS
 #else
-  (void)chars;
-  (void)i;
+  static_cast<void>(chars);
+  static_cast<void>(i);
   return false;
 #endif // FASTFLOAT_SSE2
 }
@@ -601,7 +601,7 @@
   FASTFLOAT_IF_CONSTEXPR17(
       (std::is_same<T, std::uint8_t>::value && sizeof(UC) == 1)) {
     if (base == 10) {
-      const size_t len = (size_t)(pend - p);
+      const size_t len = static_cast<size_t>(pend - p);
       if (len == 0) {
         if (has_leading_zeros) {
           value = 0;
@@ -646,9 +646,10 @@
 
       uint32_t magic =
           ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u;
-      uint32_t tz = (uint32_t)countr_zero_32(magic); // 7, 15, 23, 31, or 32
+      uint32_t tz =
+          static_cast<uint32_t>(countr_zero_32(magic)); // 7, 15, 23, 31, or 32
       uint32_t nd = (tz == 32) ? 4 : (tz >> 3);
-      nd = (uint32_t)(nd < len ? nd : len);
+      nd = static_cast<uint32_t>(nd < len ? nd : len);
       if (nd == 0) {
         if (has_leading_zeros) {
           value = 0;
@@ -684,7 +685,7 @@
         answer.ptr = p + nd;
         return answer;
       }
-      value = (uint8_t)((0x640a01 * digits) >> 24);
+      value = static_cast<uint8_t>((0x640a01 * digits) >> 24);
       answer.ec = std::errc();
       answer.ptr = p + nd;
       return answer;
diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h
index 74901e3..665debb 100644
--- a/include/fast_float/bigint.h
+++ b/include/fast_float/bigint.h
@@ -619,8 +619,8 @@
       // Work around clang bug https://godbolt.org/z/zedh7rrhc
       // This is similar to https://github.com/llvm/llvm-project/issues/47746,
       // except the workaround described there don't work here
-      FASTFLOAT_TRY(small_mul(
-          vec, limb(((void)small_power_of_5[0], small_power_of_5[exp]))));
+      FASTFLOAT_TRY(small_mul(vec, limb((static_cast<void>(small_power_of_5[0]),
+                                         small_power_of_5[exp]))));
     }
 
     return true;
diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h
index c2c83b0..70085be 100644
--- a/include/fast_float/digit_comparison.h
+++ b/include/fast_float/digit_comparison.h
@@ -400,8 +400,8 @@
   round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
     round_nearest_tie_even(
         a, shift, [ord](bool is_odd, bool _, bool __) -> bool {
-          (void)_;  // not needed, since we've done our comparison
-          (void)__; // not needed, since we've done our comparison
+          static_cast<void>(_);  // not needed, since we've done our comparison
+          static_cast<void>(__); // not needed, since we've done our comparison
           if (ord > 0) {
             return true;
           } else if (ord < 0) {
diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h
index de39fdd..2fc3549 100644
--- a/include/fast_float/float_common.h
+++ b/include/fast_float/float_common.h
@@ -225,12 +225,16 @@
 
 #ifndef FASTFLOAT_ASSERT
 #define FASTFLOAT_ASSERT(x)                                                    \
-  { ((void)(x)); }
+  {                                                                            \
+    static_cast<void>(x);                                                      \
+  }
 #endif
 
 #ifndef FASTFLOAT_DEBUG_ASSERT
 #define FASTFLOAT_DEBUG_ASSERT(x)                                              \
-  { ((void)(x)); }
+  {                                                                            \
+    static_cast<void>(x);                                                      \
+  }
 #endif
 
 // rust style `try!()` macro, or `?` operator
@@ -509,7 +513,7 @@
   // Search the mask data from most significant bit (MSB)
   // to least significant bit (LSB) for a set bit (1).
   _BitScanReverse64(&leading_zero, input_num);
-  return (int)(63 - leading_zero);
+  return static_cast<int>(63 - leading_zero);
 #else
   return leading_zeroes_generic(input_num);
 #endif
@@ -556,7 +560,7 @@
 #ifdef FASTFLOAT_VISUAL_STUDIO
   unsigned long trailing_zero = 0;
   if (_BitScanForward(&trailing_zero, input_num)) {
-    return (int)trailing_zero;
+    return static_cast<int>(trailing_zero);
   }
   return 32;
 #else
@@ -566,18 +570,21 @@
 
 // slow emulation routine for 32-bit
 fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) {
-  return x * (uint64_t)y;
+  return x * static_cast<uint64_t>(y);
 }
 
 fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
 umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) {
-  uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);
-  uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);
-  uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));
-  uint64_t adbc_carry = (uint64_t)(adbc < ad);
+  uint64_t ad =
+      emulu(static_cast<uint32_t>(ab >> 32), static_cast<uint32_t>(cd));
+  uint64_t bd = emulu(static_cast<uint32_t>(ab), static_cast<uint32_t>(cd));
+  uint64_t adbc =
+      ad + emulu(static_cast<uint32_t>(ab), static_cast<uint32_t>(cd >> 32));
+  uint64_t adbc_carry = static_cast<uint64_t>(adbc < ad);
   uint64_t lo = bd + (adbc << 32);
-  *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
-        (adbc_carry << 32) + (uint64_t)(lo < bd);
+  *hi =
+      emulu(static_cast<uint32_t>(ab >> 32), static_cast<uint32_t>(cd >> 32)) +
+      (adbc >> 32) + (adbc_carry << 32) + static_cast<uint64_t>(lo < bd);
   return lo;
 }
 
@@ -612,7 +619,7 @@
                                    !defined(_M_ARM64) && !defined(__GNUC__))
   answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
 #elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__)
-  __uint128_t r = ((__uint128_t)a) * b;
+  __uint128_t r = static_cast<__uint128_t>(a) * b;
   answer.low = uint64_t(r);
   answer.high = uint64_t(r >> 64);
 #else
@@ -874,7 +881,7 @@
 inline constexpr std::float16_t
 binary_format<std::float16_t>::exact_power_of_ten(int64_t power) {
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)powers_of_ten[0], powers_of_ten[power];
+  return static_cast<void>(powers_of_ten[0]), powers_of_ten[power];
 }
 
 template <>
@@ -918,7 +925,7 @@
   // power >= 0 && power <= 4
   //
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)max_mantissa[0], max_mantissa[power];
+  return static_cast<void>(max_mantissa[0]), max_mantissa[power];
 }
 
 template <>
@@ -997,7 +1004,7 @@
 inline constexpr std::bfloat16_t
 binary_format<std::bfloat16_t>::exact_power_of_ten(int64_t power) {
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)powers_of_ten[0], powers_of_ten[power];
+  return static_cast<void>(powers_of_ten[0]), powers_of_ten[power];
 }
 
 template <>
@@ -1041,7 +1048,7 @@
   // power >= 0 && power <= 3
   //
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)max_mantissa[0], max_mantissa[power];
+  return static_cast<void>(max_mantissa[0]), max_mantissa[power];
 }
 
 template <>
@@ -1098,7 +1105,7 @@
   // power >= 0 && power <= 22
   //
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)max_mantissa[0], max_mantissa[power];
+  return static_cast<void>(max_mantissa[0]), max_mantissa[power];
 }
 
 template <>
@@ -1108,20 +1115,20 @@
   // power >= 0 && power <= 10
   //
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)max_mantissa[0], max_mantissa[power];
+  return static_cast<void>(max_mantissa[0]), max_mantissa[power];
 }
 
 template <>
 inline constexpr double
 binary_format<double>::exact_power_of_ten(int64_t power) {
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)powers_of_ten[0], powers_of_ten[power];
+  return static_cast<void>(powers_of_ten[0]), powers_of_ten[power];
 }
 
 template <>
 inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
   // Work around clang bug https://godbolt.org/z/zedh7rrhc
-  return (void)powers_of_ten[0], powers_of_ten[power];
+  return static_cast<void>(powers_of_ten[0]), powers_of_ten[power];
 }
 
 template <> inline constexpr int binary_format<double>::largest_power_of_ten() {
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 19f2452..f8cc134 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -49,7 +49,7 @@
       target_compile_options(${TEST_NAME} PUBLIC /EHsc)
     endif()
     if(NOT WIN32)
-      target_compile_options(${TEST_NAME} PUBLIC -Werror -Wall -Wextra -Weffc++)
+      target_compile_options(${TEST_NAME} PUBLIC -Werror -Wall -Wextra -Weffc++ -Wold-style-cast)
       target_compile_options(${TEST_NAME} PUBLIC -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wsign-conversion)
     endif()
     target_link_libraries(${TEST_NAME} PUBLIC fast_float supplemental-data)
diff --git a/tests/basictest.cpp b/tests/basictest.cpp
index dba36e8..f9abefd 100644
--- a/tests/basictest.cpp
+++ b/tests/basictest.cpp
@@ -1065,7 +1065,7 @@
   do {                                                                         \
     constexpr int verify_comptime_var =                                        \
         (basic_test<Diag::comptime>(__VA_ARGS__), 0);                          \
-    (void)verify_comptime_var;                                                 \
+    static_cast<void>(verify_comptime_var);                                    \
   } while (false)
 
 #define verify_options_runtime(...)                                            \
@@ -1077,7 +1077,7 @@
   do {                                                                         \
     constexpr int verify_options_comptime_var =                                \
         (basic_test<Diag::comptime>(__VA_ARGS__, options), 0);                 \
-    (void)verify_options_comptime_var;                                         \
+    static_cast<void>(verify_options_comptime_var);                            \
   } while (false)
 
 #if defined(FASTFLOAT_CONSTEXPR_TESTS)
diff --git a/tests/exhaustive32_midpoint.cpp b/tests/exhaustive32_midpoint.cpp
index d1fc160..8feba7d 100644
--- a/tests/exhaustive32_midpoint.cpp
+++ b/tests/exhaustive32_midpoint.cpp
@@ -61,7 +61,7 @@
 }
 
 void strtof_from_string(char const *st, float &d) {
-  char *pr = (char *)st;
+  char *pr = const_cast<char *>(st);
 #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) ||     \
     defined(sun) || defined(__sun)
   d = cygwin_strtof_l(st, &pr);
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 69d2a31..b0d3b20 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -125,7 +125,7 @@
 template <typename T> void strtod_from_string(std::string const &st, T &d);
 
 template <> void strtod_from_string(std::string const &st, double &d) {
-  char *pr = (char *)st.c_str();
+  char *pr = const_cast<char *>(st.c_str());
 #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) ||     \
     defined(sun) || defined(__sun)
   d = cygwin_strtod_l(pr, &pr);
@@ -142,7 +142,7 @@
 }
 
 template <> void strtod_from_string(std::string const &st, float &d) {
-  char *pr = (char *)st.c_str();
+  char *pr = const_cast<char *>(st.c_str());
 #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) ||     \
     defined(sun) || defined(__sun)
   d = cygwin_strtof_l(st.c_str(), &pr);