-
-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use of macros for math functions causes unexpected results when argument has side effect #85
Comments
I can confirm this multiple expression evaluation problem has come up for people using Teensy. The solution is not so simple, because the C++ std namespace also has min & max, and bringing in those headers causes all sorts of other compatibility headaches. These functions/macros are also needed for plain C, which is seldom used in the Arduino world, but failure to consider it will break some programs. Here's a conversation from earlier this year about some of the details: |
All crear Paul. |
Maybe make both a templated function and a macro that calls the templated function? That would avoid the multiple call issue AND the namespace clash. template<typename T> T &Max(T &a, T &b) { return (a>=b) ? a : b; }
template<typename T> const T &Max(const T &a, const T &b) { return (a>=b) ? a : b; }
#define max(a, b) Max((a), (b)) Some related discussion (about |
(Note: The first half of this post is somewhat irrelevant, since what I suggest here was already implemented, so feel free to skip the first half) Having a macro that calls a template function does not actually fix the namespace clash. Consider
and later:
The `std::max`` will still trigger the macro, breaking the build. I would say that there should not be macros for this at all (macros are fragile in general, but especially when they use names that are so likely to be used elsewhere too), just use expose the C++ templated function directly. This does need C++ templates to make sure the typing stays more or less the same as the current macros. For C, that means there are two options:
Already implementedI was halfway writing an example of how such a template function could look like, when I noticed that @facchinm actually already implemented exactly what I was suggesting above for the 30e4397#diff-b61d0ca976d0e73288ab501219df735a Even more, he added a nice trick for the C macro version using "statement expressions" to store both parameters in local variables to prevent double evaluation. Left to implementSo I think that this issue is already solved for the |
This replaces the macros in AvrMath.h with template functions when included from C++. This prevents name clashes with e.g. the `std::min` function or similar methods or namespace-local functions. For C, this still uses a macro (lacking templates), but an improved version that prevents double evaluation of arguments. This code is based on the ArduinoCore-API repository, which is in the process of become the single source of all non-architecture-specific Arduino API code: https://github.com/arduino/ArduinoCore-API/blob/master/api/Common.h There, only `min` and `max` have been replaced by template functions, but others will probably follow as well: arduino/ArduinoCore-API#85
I implement some of these other functions in the template+macro style for another project here: ianfixes/arduino_ci@5fce911 Those could serve as a basis for fixing them here too. |
This replaces the macros in AvrMath.h with template functions when included from C++. This prevents name clashes with e.g. the `std::min` function or similar methods or namespace-local functions. For C, this still uses a macro (lacking templates), but an improved version that prevents double evaluation of arguments. This code is based on the ArduinoCore-API repository, which is in the process of become the single source of all non-architecture-specific Arduino API code: https://github.com/arduino/ArduinoCore-API/blob/master/api/Common.h There, only `min` and `max` have been replaced by template functions, but others will probably follow as well: arduino/ArduinoCore-API#85 This fixes Arduino-CI#133.
This replaces the macros in AvrMath.h with template functions when included from C++. This prevents name clashes with e.g. the `std::min` function or similar methods or namespace-local functions. For C, this still uses a macro (lacking templates), but an improved version that prevents double evaluation of arguments. This code is based on the ArduinoCore-API repository, which is in the process of become the single source of all non-architecture-specific Arduino API code: https://github.com/arduino/ArduinoCore-API/blob/master/api/Common.h There, only `min` and `max` have been replaced by template functions, but others will probably follow as well: arduino/ArduinoCore-API#85 This fixes Arduino-CI#133.
This replaces the macros in AvrMath.h with template functions when included from C++. This prevents name clashes with e.g. the `std::min` function or similar methods or namespace-local functions. For C, this still uses a macro (lacking templates), but an improved version that prevents double evaluation of arguments. This code is based on the ArduinoCore-API repository, which is in the process of become the single source of all non-architecture-specific Arduino API code: https://github.com/arduino/ArduinoCore-API/blob/master/api/Common.h There, only `min` and `max` have been replaced by template functions, but others will probably follow as well: arduino/ArduinoCore-API#85 This fixes Arduino-CI#133.
This replaces the macros in AvrMath.h with template functions when included from C++. This prevents name clashes with e.g. the `std::min` function or similar methods or namespace-local functions. For C, this still uses a macro (lacking templates), but an improved version that prevents double evaluation of arguments. This code is based on the ArduinoCore-API repository, which is in the process of become the single source of all non-architecture-specific Arduino API code: https://github.com/arduino/ArduinoCore-API/blob/master/api/Common.h There, only `min` and `max` have been replaced by template functions, but others will probably follow as well: arduino/ArduinoCore-API#85 This fixes Arduino-CI#133.
The math macros came up in the AVR core again (though for somewhat unrelated reasons) and prompted some discussion about changing the First off, let me repeat a question from a previous comment: If they should, then I think they should also be converted to template functions, falling back to macros for C only, like the other functions mentioned in this issue. Additionally, for abs, I would suggest changing the expression from
See arduino/ArduinoCore-avr#406 for additional discussion. |
Hi folks,
I know it has been discussed already here and there...
I find semantically wrong the fact that the following math functions are implemented as macros:
abs, min, max, constrain, round... and let me add bitWrite to the list.
It is well known that using these function the way the rest of the world does, introduces faults, and therefore generates failures.
Writing something like abs(cos(x) - 123 * sq(sin(x)) would introduce redundant calculations, just a crazy delay in this case...
Writing something like abs(a += b) or abs(i++) just introduces a fault... it does something different (wrong in fact).
Assuming that using template and inline functions would solve the issue with no extra executable space taken, I would like to know if there is any other good reason why those dangerous
macro definitions are still in force.
Kind regards,
Iacopo.
The text was updated successfully, but these errors were encountered: