min, max, abs.. are macroses?

pYro_65:
Technically unexpected behaviour is a bug.
Documentation specifying the 'unexpected behaviour' makes it an 'undefined behaviour' and explicitly leaves it to the programmer to investigate, this however is not the case.

Vastly different to having an explicitly defined error in your own code.

However I agree, the solution needs to be workable in C & C++.

that is as easy as a #ifdef for the C++ define, which leaves reason to provide a safer version when possible.

The C language has alot of unexpected behaviors that do not qualify as bugs as there
are many folks that are not intimately familiar with many of the low level details around
precedence, char type handling and promotion.

In this case I did say it was a bug.
No different than a math library generating an incorrect sine value or floating point calculation.
The bug just happens to be in system supplied code rather than a users code.

There is no need to punish the C code in favor of C++ when looking for solutions
especially when, as I've shown, it is possible to write better macros that work
properly for both C and C++

--- bill

@bperrybap: Are you claiming that the Arduino folks, for the foreseeable future, will only be using GCC?

I also have not seen any modern free optimising compilers that do not support C++ apart from non standard implementations. I'm sure they exist, but are their optimisations worth a grain of salt.

No. I have no information either way.

But given the low cost availability and realibility of gcc for so many different platforms including
ARM, it seemed like a natural fit.

I also read a thread over on the diydrones site about ardupilot from back in Sep 2011.
There was some Arduino and Atmel bashing going on.
Massimo Banzi made a comment about having an ARM environment with gdb up and working with a new IDE
prototype.

Seems to at least "smell" like gcc is going to be solution for the foreseeable future.

--- bill

bperrybap:
I believe that a final solution needs to work for both C and C++

Why for C?

Why create a C++ only solution?

Not everything in Arduino is C++
There is core code that is C and there are some libraries that use C++ wrappers on top of C code.

bperrybap:
Why create a C++ only solution?

At this point, there is no reason not to.

Not everything in Arduino is C++ ... There is core code that is C

The list is short...
WInterrupts.c
wiring.c
wiring_analog.c
wiring_digital.c
wiring_pulse.c
wiring_shift.c

and there are some libraries that use C++ wrappers on top of C code.

The list is even shorter...
twi.c

None of those modules use the macros in question.

Why does the solution need to work for C?

While the code that is provided by the Arduino development environment,
(core code and libraries), does not have any C code that currently uses these macros

[quote author=Coding Badly link=topic=84364.msg650144#msg650144 date=1326358679]
At this point, there is no reason not to.[/quote]
seems to a bit of an overstatement with respect to creating a C++ only solution.

Why does the solution need to work for C?

So that it can be finally be put to bed rather than having to revisit this again
in the future when something in a C module "breaks".
Maybe it is a 3rd party library, or heaven forbid some
new C code in say the Due C core code wants/needs to use these type of macros.

IMHO, this kind of stuff really should be done by the compiler and LibC people rather than being done
in individual projects.

Of course, another approach, which would carry on in the seemingly odd, IMHO, Arduino/Wiring Language
"Re-Inventing the Wheel Syndrome", would be to create new Class/Macro/Template "functions"
with names like Min(), Max(), Abs(), Constrain(), and Round() that do what the old functions/macros
did.

But even if you do that, you still need to fix the existing min()/max() ... macros.

--- bill

bperrybap:
But even if you do that, you still need to fix the existing min()/max() ... macros.

Simple solution would be to wrap the old-school stuff in the #else of #ifdef __cplusplus. That way, the modern folks can have a well-behaved compiler-driven solution, and people who for some reason like C and Arduino, can have something that works.

Moreover, the focus in Arduino is folks who are new to all this. These folks will not need C, and they are more likely to be tripped up by accidentally using 'max' somewhere in their code and getting arcane error messages. I think it's fair to say that anyone using C on Arduino knows what they're doing, and can pull in a C implementation of min/max without any problem.

I guess the chief danger is that a user's Arduino habits would suddenly cause them to write non-working code in a C environment. A C++ only solution would cause C++ to behave differently than C (silently. Invisibly.)

this kind of stuff really should be done by the compiler and LibC people

Agreed. It looks as though "abs" has already been handled by the compiler.

"The ISO C90 functions abs, cos, exp, fabs, fprintf, fputs, labs, log, memcmp, memcpy, memset, printf, putchar, puts, scanf, sin, snprintf, sprintf, sqrt, sscanf, strcat, strchr, strcmp, strcpy, strcspn, strlen, strncat, strncmp, strncpy, strpbrk, strrchr, strspn, strstr, vprintf and vsprintf are all recognized as built-in functions unless -fno-builtin is specified (or -fno-builtin-function is specified for an individual function). All of these functions have corresponding versions prefixed with _builtin."

maniacbug

Simple solution would be to wrap the old-school stuff in the #else of #ifdef __cplusplus. That way, the modern folks can have a well-behaved compiler-driven solution, and people who for some reason like C and Arduino, can have something that works.

I agree this is a solution. I would like to share this thought:
This solution will create situations where code works in one situation and it doesn't in another. Newbies will not realize they moved their code from C++ to C (or the other way around) and will be completely puzzled. At that point in time there will only be a very small number of people who still know macro behavior and the specific Arduino implementation.
And then I ask myself (without implying an answer) What is worse? A commonly known drawback with little consequences or a rare unknown drawback with little consequences?

Best regards
Jantje

The code in Reply #7 is out. It requires both parameters to be the same datatype. New users have enough problems with datatypes. Forcing them to learn typecasting makes the pain even worse.

The code in Reply #9 is out. It does not compile with the GCC version that ships with Arduino nor with the latest WinAVR.

The code in Reply #11 has the same problem as the code in Reply #7.

Which leaves the macro in Reply #13 and inline functions. abs works very nicely as an inline function. min and max not so much (too many combinations). At this point, the only one left standing is the macro in reply #13.

A few points of interest: The code generation varies a bit and is not consistent. Sometimes the "old" macro produces slightly better code. Sometimes the template does. Sometimes the "new" macro does. Basically, all the solutions have at least one code generation quirk. The random function appears to include an exception handler stack frame for some reason (lots of unnecessary code). The round macro fails to work correctly for values past ±8388609. The GCC / Libc round function works correctly.

If you don't mind my asking:

Why are these macros defined at all?
Isn't it more difficult to have to remember the "gotchas" of working with macros than it is to write your own code for these things when you need it?
We're not talking about anything fancy here. I mean, how hard is it to write something like this? x = (y>=0?y:-y);

As for squaring, is there any reason for the compiler not to handle y = pow(x,2) by using the obvious optimization?

There is no point contemplating why they exist. There is a non-zero number of users who have used them so they cannot be removed.

And if they annoy you, you can always #undef them out so they don't annoy again.

A problem with implementing them as a function is STACK USAGE - Will they use more stack space (only 2K RAM, remember?) as a function or as a macro?

Stack is much more limited than is program memory. While it might be good to optimize for FLASH usage, you must not forget limited RAM.

kf2qd:
A problem with implementing them as a function is STACK USAGE - Will they use more stack space (only 2K RAM, remember?) as a function or as a macro?

For normal# functions with a few bytes of parameters (like min(int,int)) only the return address is pushed on the stack (two bytes). The parameters are passed in registers.

For inline functions the code is inserted at the call-point so not even the return address is pushed.

Stack is much more limited than is program memory. While it might be good to optimize for FLASH usage, you must not forget limited RAM.

In terms of SRAM usage, there is essentially no difference in the choices discussed here. The optimizer occasionally makes a minor mistake leading to one or two bytes unnecessarily being pushed but that behaviour seems to be independent of the implementation.

# As opposed to inline functions.

I don't see a real problem with using the macros I just wish the reference would say they are macros and also have an example of how the usage may fail so people can avoid it without having in-depth c/c++ knowledge.

The biggest drawback of these macros is the inability to use those macro names in your own code. A range class for example would benefit from members named min & max over something like LowVal and HighVal for example.

pYro_65:
The biggest drawback of these macros is the inability to use those macro names in your own code. A range class for example would benefit from members named min & max over something like LowVal and HighVal for example.

That's a problem with any language except for Forth. Reserved keywords and such are an issue with any language. Only Forth allows you to redefine a WORD without damaging the code that used the old version.