|
22 | 22 | #else |
23 | 23 | #include <sys/types.h> |
24 | 24 | #endif |
| 25 | +#include <stdio.h> // snprintf |
| 26 | +#include <stdlib.h> // abs |
25 | 27 |
|
26 | 28 | /** |
27 | 29 | * @todo Consider shortening the namespace name to its last component |
@@ -176,6 +178,34 @@ namespace com::saxbophone::sxpsxfp { |
176 | 178 | // can't use a right-shift here due to it not handling negative values properly |
177 | 179 | return this->_raw_value / Fixed::SCALE; |
178 | 180 | } |
| 181 | + /** |
| 182 | + * @brief Stringifies the Fixed-point value to a C-string |
| 183 | + * @param buffer pointer to array of `char`. Must be non-null and pointing to buffer of size `buffer_size`. |
| 184 | + * @param[out] buffer_size size of `buffer`. Should be at least `15`. |
| 185 | + * @returns `false` if buffer could not be written, because buffer_size wasn't big enough |
| 186 | + * @returns `true` if buffer was written |
| 187 | + * @note Although conforming C-libraries check if `buffer == nullptr` for you, the implementation of `vsnprintf()` |
| 188 | + * in libPSn00bSDK, which this project is intended for use with, doesn't seem to check if `buffer == NULL`, hence |
| 189 | + * the need to check it here. |
| 190 | + */ |
| 191 | + constexpr bool to_c_str(char* buffer, size_t buffer_size) const { |
| 192 | + // don't write to a null-pointer! |
| 193 | + if (buffer == nullptr) { return false; } |
| 194 | + // need at least 14 characters and 1 for the null-terminator |
| 195 | + if (buffer_size < 15) { return false; } // refuse if not at least this many in buffer |
| 196 | + int decimal_part = this->_raw_value / 4096; // floor-divide |
| 197 | + // decompose the fractional part into an unsigned int to allow us to scale it up for more decimal places |
| 198 | + unsigned int remainder = ((unsigned int)abs(this->_raw_value)) % 4096; |
| 199 | + // 1M is the maximum we can scale it up without overflow, since 4096*1M = 4096M, compared to max uint32 = ~4294M |
| 200 | + unsigned int fractional_part = (remainder * 1'000'000) / 4096; // this gives us 6 decimal places |
| 201 | + // can't print a negative sign if negative but decimal_part is zero |
| 202 | + if (this->_raw_value < 0 and decimal_part == 0) { |
| 203 | + snprintf(buffer, buffer_size, "-0.%06u", fractional_part); |
| 204 | + } else { // otherwise, we can rely on snprintf() to do it for us |
| 205 | + snprintf(buffer, buffer_size, "%d.%06u", decimal_part, fractional_part); |
| 206 | + } |
| 207 | + return true; |
| 208 | + } |
179 | 209 | /** |
180 | 210 | * @brief Prefix increment operator |
181 | 211 | */ |
|
0 commit comments