docs/ARDUINO_MACRO_CONFLICTS.md
Arduino.h (and Arduino AVR in particular) defines several common function names as macros:
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
These macros conflict with:
std::min, std::max, std::abs, std::round)fl::numeric_limits<T>::max(), fl::numeric_limits<T>::min())Wrap the function name in parentheses to prevent macro expansion:
// ❌ WRONG - macro will expand
u32 oldest_time = fl::numeric_limits<u32>::max();
// Error: macro "max" requires 2 arguments, but only 1 given
// ✅ CORRECT - parentheses prevent macro expansion
u32 oldest_time = (fl::numeric_limits<u32>::max)();
Pattern:
// Instead of:
fl::numeric_limits<T>::max()
fl::numeric_limits<T>::min()
// Use:
(fl::numeric_limits<T>::max)()
(fl::numeric_limits<T>::min)()
When to use: Call sites where you need to invoke max(), min(), abs(), or round().
Use #pragma push_macro/#pragma pop_macro around function definitions:
// Arduino.h defines round as a macro, so we need to temporarily hide it
#pragma push_macro("round")
#undef round
float round_impl_float(float value) {
return ::roundf(value);
}
double round_impl_double(double value) {
return ::round(value);
}
#pragma pop_macro("round")
Pattern:
#pragma push_macro("macro_name") // Save current definition
#undef macro_name // Remove macro temporarily
// ... declare/define functions named macro_name ...
#pragma pop_macro("macro_name") // Restore original definition
When to use: Function definitions or header sections where you need to declare functions with conflicting names.
FastLED provides fl/undef.h which undefines common conflicting macros:
#include "fl/undef.h" // Undefines min, max, abs, round
// Now safe to declare functions with these names
static T min() { ... }
static T max() { ... }
Note: This permanently removes the macros in that compilation unit. Use push/pop if you need to restore them.
The following files were fixed to prevent Arduino macro conflicts:
src/fl/hash_map_lru.h - (fl::numeric_limits<u32>::max)()src/fl/noise_woryley.cpp.hpp - (fl::numeric_limits<i32>::max)()src/fl/task.cpp.hpp - (numeric_limits<uint32_t>::max)() (2 locations)src/fl/fx/video/pixel_stream.cpp.hpp - (fl::numeric_limits<int32_t>::max)()src/fl/spi/parallel_device.h - Default parameter (fl::numeric_limits<uint32_t>::max)()src/fl/json.cpp.hpp - Multiple (max)() and (min)() callssrc/fl/traverse_grid.h - 8 instances of (max)() in ternary expressionssrc/platforms/arm/d21/spi_hw_2_samd21.cpp.hpp - Default parametersrc/platforms/arm/d51/spi_hw_2_samd51.cpp.hpp - Default parametersrc/platforms/arm/d51/spi_hw_4_samd51.cpp.hpp - Default parametersrc/platforms/arm/nrf52/spi_hw_2_nrf52.cpp.hpp - Comparison expressionssrc/fl/stl/malloc.cpp.hpp - abs() function definitionsrc/fl/stl/math.cpp.hpp - round_impl_float() and round_impl_double() functionssrc/fl/stl/limits.h - Uses push/pop around numeric_limits definitionsnumeric_limits<T>::max() or ::min() in Arduino-compatible code// Use (max)() to prevent macro expansion by Arduino.h's max macro
u32 value = (fl::numeric_limits<u32>::max)();
src/fl/undef.h - Utility header for undefining conflicting macrossrc/fl/stl/limits.h - Already uses push/pop pattern for numeric_limits definitionssrc/third_party/arduinojson/json.h - Example of macro handling in third-party code#pragma push_macro/#pragma pop_macro - GCC/Clang extensions (also MSVC)